Skip to content

Commit ad298c7

Browse files
committed
Asterisk imports parsing; Pussyfooting around stdlib
1 parent a0ec684 commit ad298c7

File tree

15 files changed

+303
-103
lines changed

15 files changed

+303
-103
lines changed

bin/asc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ if (args.help || args._.length < 1) {
6666
"Syntax: asc [options] [entryFile ...]",
6767
"",
6868
"Examples: asc hello.ts",
69-
" asc hello.ts -b hello.wasm -t hello.wast -a hello.js",
69+
" asc hello.ts -b hello.wasm -t hello.wast",
7070
" asc hello1.ts hello2.ts -b -O > hello.wasm",
7171
"",
7272
"Options:"

src/ast.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,18 @@ export abstract class Node {
391391
const stmt: ImportStatement = new ImportStatement();
392392
stmt.range = range;
393393
for (let i: i32 = 0, k: i32 = (stmt.declarations = declarations).length; i < k; ++i) declarations[i].parent = stmt;
394+
stmt.namespaceName = null;
395+
stmt.path = path;
396+
stmt.normalizedPath = resolvePath(normalizePath(path.value), range.source.normalizedPath);
397+
stmt.internalPath = mangleInternalPath(stmt.normalizedPath);
398+
return stmt;
399+
}
400+
401+
static createImportAll(identifier: IdentifierExpression, path: StringLiteralExpression, range: Range): ImportStatement {
402+
const stmt: ImportStatement = new ImportStatement();
403+
stmt.range = range;
404+
stmt.declarations = null;
405+
stmt.namespaceName = identifier;
394406
stmt.path = path;
395407
stmt.normalizedPath = resolvePath(normalizePath(path.value), range.source.normalizedPath);
396408
stmt.internalPath = mangleInternalPath(stmt.normalizedPath);
@@ -1569,8 +1581,10 @@ export class ImportStatement extends Statement {
15691581

15701582
kind = NodeKind.IMPORT;
15711583

1572-
/** Array of member declarations. */
1573-
declarations: ImportDeclaration[];
1584+
/** Array of member declarations or `null` if an asterisk import. */
1585+
declarations: ImportDeclaration[] | null;
1586+
/** Name of the local namespace, if an asterisk import. */
1587+
namespaceName: IdentifierExpression | null;
15741588
/** Path being imported from. */
15751589
path: StringLiteralExpression;
15761590
/** Normalized path. */
@@ -1579,13 +1593,22 @@ export class ImportStatement extends Statement {
15791593
internalPath: string;
15801594

15811595
serialize(sb: string[]): void {
1582-
sb.push("import {\n");
1583-
for (let i: i32 = 0, k: i32 = this.declarations.length; i < k; ++i) {
1584-
if (i > 0)
1585-
sb.push(",\n");
1586-
this.declarations[i].serialize(sb);
1596+
if (this.declarations) {
1597+
sb.push("import {\n");
1598+
for (let i: i32 = 0, k: i32 = this.declarations.length; i < k; ++i) {
1599+
if (i > 0)
1600+
sb.push(",\n");
1601+
this.declarations[i].serialize(sb);
1602+
}
1603+
sb.push("\n}");
1604+
} else {
1605+
sb.push("import * as ");
1606+
if (this.namespaceName)
1607+
this.namespaceName.serialize(sb);
1608+
else
1609+
throw new Error("missing asterisk import identifier");
15871610
}
1588-
sb.push("\n} from ");
1611+
sb.push(" from ");
15891612
this.path.serialize(sb);
15901613
}
15911614
}

src/compiler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2093,7 +2093,7 @@ export class Compiler extends DiagnosticEmitter {
20932093
return this.module.createBinary(BinaryOp.EqF64, operand, this.module.createF64(0));
20942094
}
20952095
op = this.currentType.isLongInteger
2096-
? UnaryOp.EqzI64 // TODO: does this yield i64 0/1?
2096+
? UnaryOp.EqzI64
20972097
: UnaryOp.EqzI32;
20982098
this.currentType = Type.bool;
20992099
break;

src/parser.ts

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export class Parser extends DiagnosticEmitter {
9393
const normalizedPath: string = normalizePath(path);
9494
for (let i: i32 = 0, k: i32 = this.program.sources.length; i < k; ++i)
9595
if (this.program.sources[i].normalizedPath == normalizedPath)
96-
throw new Error("duplicate source");
96+
return; // already parsed
9797
this.seenlog.add(normalizedPath);
9898

9999
const source: Source = new Source(path, text, isEntry);
@@ -104,10 +104,10 @@ export class Parser extends DiagnosticEmitter {
104104

105105
while (!tn.skip(Token.ENDOFFILE)) {
106106
const statement: Statement | null = this.parseTopLevelStatement(tn);
107-
if (!statement)
108-
return;
109-
statement.parent = source;
110-
source.statements.push(statement);
107+
if (statement) {
108+
statement.parent = source;
109+
source.statements.push(statement);
110+
}
111111
}
112112
}
113113

@@ -201,7 +201,7 @@ export class Parser extends DiagnosticEmitter {
201201
default:
202202
if (hasModifier(ModifierKind.EXPORT, modifiers)) {
203203
tn.reset();
204-
statement = this.parseExport(tn, modifiers); // TODO: why exactly does this have modifiers again?
204+
statement = this.parseExport(tn, modifiers); // TODO: why exactly does this have modifiers again? 'declare'?
205205
} else {
206206
if (modifiers) {
207207
if (modifier = getModifier(ModifierKind.DECLARE, modifiers))
@@ -713,13 +713,10 @@ export class Parser extends DiagnosticEmitter {
713713

714714
let isGetter: bool = false;
715715
let isSetter: bool = false;
716-
if (tn.skip(Token.GET)) {
716+
if (isGetter = tn.skip(Token.GET))
717717
modifiers = addModifier(Node.createModifier(ModifierKind.GET, tn.range()), modifiers);
718-
isGetter = true;
719-
} else if (tn.skip(Token.SET)) { // can't be both
718+
else if (isSetter = tn.skip(Token.SET)) // can't be both
720719
modifiers = addModifier(Node.createModifier(ModifierKind.SET, tn.range()), modifiers);
721-
isSetter = true;
722-
}
723720

724721
if (tn.skip(Token.CONSTRUCTOR) || tn.skip(Token.IDENTIFIER)) { // order is important
725722
const identifier: IdentifierExpression = tn.token == Token.CONSTRUCTOR
@@ -899,10 +896,12 @@ export class Parser extends DiagnosticEmitter {
899896
}
900897

901898
parseImport(tn: Tokenizer): ImportStatement | null {
902-
// at 'import': '{' (ImportMember (',' ImportMember)*)? '}' 'from' StringLiteral ';'?
903-
const startRange: Range = tn.range();
899+
// at 'import': ('{' (ImportMember (',' ImportMember)*)? '}' | '*' 'as' Identifier) 'from' StringLiteral ';'?
900+
const startPos: i32 = tn.tokenPos;
901+
let members: ImportDeclaration[] | null = null;
902+
let namespaceName: IdentifierExpression | null = null;
904903
if (tn.skip(Token.OPENBRACE)) {
905-
const members: ImportDeclaration[] = new Array();
904+
members = new Array();
906905
if (!tn.skip(Token.CLOSEBRACE)) {
907906
do {
908907
const member: ImportDeclaration | null = this.parseImportDeclaration(tn);
@@ -915,22 +914,49 @@ export class Parser extends DiagnosticEmitter {
915914
return null;
916915
}
917916
}
918-
if (tn.skip(Token.FROM)) {
919-
if (tn.skip(Token.STRINGLITERAL)) {
920-
const path: StringLiteralExpression = Node.createStringLiteral(tn.readString(), tn.range());
921-
const ret: ImportStatement = Node.createImport(members, path, Range.join(startRange, tn.range()));
922-
if (!this.seenlog.has(ret.normalizedPath)) {
923-
this.backlog.push(ret.normalizedPath);
924-
this.seenlog.add(ret.normalizedPath);
917+
} else if (tn.skip(Token.ASTERISK)) {
918+
if (tn.skip(Token.AS)) {
919+
if (tn.skip(Token.IDENTIFIER)) {
920+
namespaceName = Node.createIdentifier(tn.readIdentifier(), tn.range());
921+
} else {
922+
this.error(DiagnosticCode.Identifier_expected, tn.range());
923+
return null;
924+
}
925+
} else {
926+
this.error(DiagnosticCode._0_expected, tn.range(), "as");
927+
return null;
928+
}
929+
} else {
930+
this.error(DiagnosticCode._0_expected, tn.range(), "{");
931+
return null;
932+
}
933+
if (tn.skip(Token.FROM)) {
934+
if (tn.skip(Token.STRINGLITERAL)) {
935+
const path: StringLiteralExpression = Node.createStringLiteral(tn.readString(), tn.range());
936+
let ret: ImportStatement;
937+
if (members) {
938+
if (!namespaceName)
939+
ret = Node.createImport(members, path, tn.range(startPos, tn.pos));
940+
else {
941+
assert(false);
942+
return null;
925943
}
926-
tn.skip(Token.SEMICOLON);
927-
return ret;
928-
} else
929-
this.error(DiagnosticCode.String_literal_expected, tn.range());
944+
} else if (namespaceName) {
945+
ret = Node.createImportAll(namespaceName, path, tn.range(startPos, tn.pos));
946+
} else {
947+
assert(false);
948+
return null;
949+
}
950+
if (!this.seenlog.has(ret.normalizedPath)) {
951+
this.backlog.push(ret.normalizedPath);
952+
this.seenlog.add(ret.normalizedPath);
953+
}
954+
tn.skip(Token.SEMICOLON);
955+
return ret;
930956
} else
931-
this.error(DiagnosticCode._0_expected, tn.range(), "from");
957+
this.error(DiagnosticCode.String_literal_expected, tn.range());
932958
} else
933-
this.error(DiagnosticCode._0_expected, tn.range(), "{");
959+
this.error(DiagnosticCode._0_expected, tn.range(), "from");
934960
return null;
935961
}
936962

@@ -1363,7 +1389,7 @@ export class Parser extends DiagnosticEmitter {
13631389
// see: http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm#climbing
13641390

13651391
parseExpressionStart(tn: Tokenizer): Expression | null {
1366-
const token: Token = tn.next();
1392+
const token: Token = tn.next(true);
13671393
const startPos: i32 = tn.tokenPos;
13681394
let expr: Expression | null = null;
13691395

src/program.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -501,11 +501,21 @@ export class Program extends DiagnosticEmitter {
501501
}
502502

503503
private initializeImports(statement: ImportStatement, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
504-
const members: ImportDeclaration[] = statement.declarations;
505-
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i) {
506-
const declaration: ImportDeclaration = members[i];
507-
this.initializeImport(declaration, statement.internalPath, queuedExports, queuedImports);
508-
}
504+
const declarations: ImportDeclaration[] | null = statement.declarations;
505+
if (declarations) {
506+
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) {
507+
const declaration: ImportDeclaration = declarations[i];
508+
this.initializeImport(declaration, statement.internalPath, queuedExports, queuedImports);
509+
}
510+
} else if (statement.namespaceName) {
511+
const internalName: string = statement.range.source.internalPath + "/" + statement.namespaceName.name;
512+
if (this.elements.has(internalName)) {
513+
this.error(DiagnosticCode.Duplicate_identifier_0, statement.namespaceName.range, internalName);
514+
return;
515+
}
516+
this.error(DiagnosticCode.Operation_not_supported, statement.range); // TODO
517+
} else
518+
assert(false);
509519
}
510520

511521
private initializeImport(declaration: ImportDeclaration, internalPath: string, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {

src/tokenizer.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,17 @@ export class Tokenizer extends DiagnosticEmitter {
731731
}
732732
}
733733

734+
// skipUntil(token1: Token, token2: Token = -1): bool {
735+
// let next: Token;
736+
// do {
737+
// if ((next = this.peek()) == Token.ENDOFFILE)
738+
// return false;
739+
// if (next == token1 || next == token2)
740+
// return true;
741+
// this.next();
742+
// } while (true);
743+
// }
744+
734745
mark(): void {
735746
this.markedPos = this.pos;
736747
this.markedToken = this.token;

src/util/charcode.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const enum CharCode {
2222
THINSPACE = 0x2009,
2323
HAIRSPACE = 0x200A,
2424
ZEROWIDTHSPACE = 0x200B,
25-
NARRINOBREAKSPACE = 0x202F,
25+
NARROWNOBREAKSPACE = 0x202F,
2626
IDEOGRAPHICSPACE = 0x3000,
2727
MATHEMATICALSPACE = 0x205F,
2828
OGHAM = 0x1680,
@@ -156,7 +156,7 @@ export function isWhiteSpace(c: i32): bool {
156156
case CharCode.NONBREAKINGSPACE:
157157
case CharCode.NEXTLINE:
158158
case CharCode.OGHAM:
159-
case CharCode.NARRINOBREAKSPACE:
159+
case CharCode.NARROWNOBREAKSPACE:
160160
case CharCode.MATHEMATICALSPACE:
161161
case CharCode.IDEOGRAPHICSPACE:
162162
case CharCode.BYTEORDERMARK:

std/assembly.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ declare function parseFloat(str: string): f64;
178178

179179
/** Class representing a sequence of values of type `T`. */
180180
declare class Array<T> {
181+
[key: number]: T;
181182

182183
/** Current maximum capacity of the array. */
183184
readonly capacity: i32;
@@ -275,3 +276,6 @@ declare function global(): any;
275276

276277
/** Annotates a method being an operator overload. */
277278
declare function operator(token: string): any;
279+
280+
declare function struct(): any;
281+
declare function size(size: usize): any;

std/assembly/array.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
@global()
22
export class Array<T> {
33

4+
private ptr: usize;
5+
46
readonly capacity: i32;
57
length: i32;
6-
ptr: usize;
78

89
constructor(capacity: i32 = 0) {
910
if (capacity < 0)

0 commit comments

Comments
 (0)