Fix some bugs and add minimal support for imports

This commit is contained in:
Sam Vervaeck 2020-02-25 18:34:17 +01:00
parent 5e111d8a65
commit efa3c4d835
7 changed files with 108 additions and 10 deletions

View file

@ -70,7 +70,7 @@ export enum SyntaxKind {
VarDecl,
FuncDecl,
ForeignDecl,
ImportDecl,
}
@ -920,6 +920,7 @@ export class VarDecl extends SyntaxBase {
kind: SyntaxKind.VarDecl = SyntaxKind.VarDecl;
constructor(
public isMutable: boolean,
public bindings: Patt,
public typeDecl: TypeDecl | null,
public value: Expr | null,
@ -952,11 +953,32 @@ export class VarDecl extends SyntaxBase {
}
export class ImportDecl {
kind: SyntaxKind.ImportDecl = SyntaxKind.ImportDecl;
constructor(
public file: string,
public span: TextSpan | null = null,
public origNode: [Syntax, Syntax] | Syntax | null = null,
public parentNode: Syntax | null = null
) {
}
*getChildren(): IterableIterator<Syntax> {
}
}
export type Decl
= Sentence
| FuncDecl
| ImportDecl
| VarDecl
export type Syntax
= Decl
| Expr

View file

@ -183,14 +183,15 @@ yargs
const compiler = new Compiler(checker, { target: "JS" })
const bundle = compiler.compile(sourceFiles)
const emitter = new Emitter()
for (const file of bundle) {
const outfiles = bundle.map(file => {
const text = emitter.emit(file);
fs.mkdirpSync('.bolt-work')
const filepath = path.join('.bolt-work', path.relative(process.cwd(), stripExtension(path.resolve(file.loc.source)) + '.js'))
const filepath = path.join('.bolt-work', path.relative(process.cwd(), stripExtension(path.resolve(file.loc.source)) + '.mjs'))
fs.writeFileSync(filepath, text, 'utf8')
spawnSync('node', [filepath], { stdio: 'inherit' })
}
return filepath
})
spawnSync('node', [outfiles[0]], { stdio: 'inherit' })
}
)

View file

@ -1,7 +1,8 @@
import {
Syntax,
SyntaxKind
SyntaxKind,
ImportDecl,
} from "./ast"
class Type {
@ -27,7 +28,7 @@ export class TypeChecker {
protected scopes = new Map<Syntax, Scope>();
createType(node: Syntax) {
protected createType(node: Syntax) {
switch (node.kind) {
case SyntaxKind.ConstExpr:
if (typeof node.value === 'bigint') {
@ -38,6 +39,10 @@ export class TypeChecker {
}
}
getImportedSymbols(node: ImportDecl) {
return [{ name: 'fac' }]
}
getScope(node: Syntax): Scope {
while (node.kind !== SyntaxKind.FuncDecl && node.kind !== SyntaxKind.SourceFile) {
node = node.parentNode!;

View file

@ -96,6 +96,31 @@ export class Compiler {
switch (node.kind) {
case SyntaxKind.ImportDecl:
preamble.push({
type: 'ImportDeclaration',
source: { type: 'Literal', value: node.file },
specifiers: this.checker.getImportedSymbols(node).map(s => ({
type: 'ImportSpecifier',
imported: { type: 'Identifier', name: s.name },
local: { type: 'Identifier', name: s.name },
})),
});
break;
case SyntaxKind.VarDecl:
const compiledValue = node.value !== null ? this.compileExpr(node.value, preamble) : null;
preamble.push({
type: 'VariableDeclaration',
kind: 'let',
declarations: [{
type: 'VariableDeclarator',
id: { type: 'Identifier', name: node.bindings.name.text },
init: compiledValue
}]
});
break;
case SyntaxKind.FuncDecl:
const params = [];
if (node.target === this.target) {

View file

@ -18,6 +18,7 @@ export class Expander {
constructor(public parser: Parser) {
this.transformers.set('fn', parser.parseFuncDecl.bind(parser))
this.transformers.set('import', parser.parseImportDecl.bind(parser))
this.transformers.set('foreign', parser.parseFuncDecl.bind(parser))
this.transformers.set('let', parser.parseVarDecl.bind(parser))
this.transformers.set('return', parser.parseRetStmt.bind(parser))

View file

@ -20,8 +20,8 @@ import {
TypeDecl,
ConstExpr,
QualName,
ForeignDecl,
CallExpr,
ImportDecl,
} from "./ast"
function describeKind(kind: SyntaxKind): string {
@ -116,6 +116,20 @@ export class Parser {
}
}
parseImportDecl(tokens: TokenStream) {
// Assuming first keyword is 'import'
tokens.get();
const t0 = tokens.get();
if (t0.kind !== SyntaxKind.StringLiteral) {
throw new ParseError(t0, [SyntaxKind.StringLiteral])
}
return new ImportDecl(t0.value, null, t0);
}
parseTypeDecl(tokens: TokenStream): TypeDecl {
const t0 = tokens.peek();
if (t0.kind === SyntaxKind.Identifier) {
@ -170,9 +184,35 @@ export class Parser {
parseVarDecl(tokens: TokenStream): VarDecl {
let isMutable = false;
let typeDecl = null;
let value = null;
// Assuming first token is 'let'
tokens.get();
const t0 = tokens.peek();
if (t0.kind === SyntaxKind.Identifier && t0.text === 'mut') {
tokens.get();
isMutable = true;
}
const bindings = this.parsePattern(tokens)
const t1 = tokens.peek();
if (t1.kind === SyntaxKind.Colon) {
tokens.get();
typeDecl = this.parseTypeDecl(tokens);
}
const t2 = tokens.peek();
if (t2.kind === SyntaxKind.EqSign) {
tokens.get();
value = this.parseExpr(tokens);
}
return new VarDecl(isMutable, bindings, typeDecl, value, null)
}
parseRetStmt(tokens: TokenStream): RetStmt {
@ -206,7 +246,7 @@ export class Parser {
let target = "Bolt";
const k0 = tokens.get();
const k0 = tokens.peek();
if (k0.kind !== SyntaxKind.Identifier) {
throw new ParseError(k0, [SyntaxKind.ForeignKeyword, SyntaxKind.FunctionKeyword])
}
@ -218,7 +258,7 @@ export class Parser {
target = l1.value;
}
const k1 = tokens.get();
if (k1.text !== 'fn') {
if (k1.kind !== SyntaxKind.Identifier || k1.text !== 'fn') {
throw new ParseError(k1, [SyntaxKind.FunctionKeyword])
}

View file

@ -23,6 +23,7 @@ import {
IntegerLiteral,
Colon,
EOS,
EqSign,
} from "./ast"
function escapeChar(ch: string) {
@ -200,6 +201,9 @@ export class Scanner {
}
switch (c0) {
case '=':
this.getChar();
return new EqSign(new TextSpan(this.file, startPos, this.currPos.clone()));
case ';':
this.getChar();
return new Semi(new TextSpan(this.file, startPos, this.currPos.clone()));