Skip to content

Commit 2c009c6

Browse files
committed
Initial element access compilation; Carefully approaching std array
1 parent dd596b0 commit 2c009c6

21 files changed

+9914
-88
lines changed

src/ast.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -363,12 +363,12 @@ export abstract class Node {
363363
stmt.decoratorKind = DecoratorKind.OPERATOR;
364364
break;
365365

366-
case "struct":
367-
stmt.decoratorKind = DecoratorKind.STRUCT;
366+
case "explicit":
367+
stmt.decoratorKind = DecoratorKind.EXPLICIT;
368368
break;
369369

370-
case "size":
371-
stmt.decoratorKind = DecoratorKind.SIZE;
370+
case "offset":
371+
stmt.decoratorKind = DecoratorKind.OFFSET;
372372
break;
373373

374374
default:
@@ -1382,8 +1382,8 @@ export const enum DecoratorKind {
13821382
CUSTOM,
13831383
GLOBAL,
13841384
OPERATOR,
1385-
STRUCT,
1386-
SIZE
1385+
EXPLICIT,
1386+
OFFSET
13871387
}
13881388

13891389
/** Depresents a decorator. */

src/builtins.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,7 +1349,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
13491349
}
13501350
arg0 = compiler.compileExpression(operands[0], usizeType);
13511351
compiler.currentType = typeArguments[0];
1352-
return module.createLoad(typeArguments[0].size >>> 3, typeArguments[0].is(TypeFlags.SIGNED | TypeFlags.INTEGER), arg0, typeArguments[0].toNativeType());
1352+
return module.createLoad(typeArguments[0].byteSize, typeArguments[0].is(TypeFlags.SIGNED | TypeFlags.INTEGER), arg0, typeArguments[0].toNativeType());
13531353

13541354
case "store": // store<T?>(offset: usize, value: T) -> void
13551355
compiler.currentType = Type.void;
@@ -1372,7 +1372,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
13721372
}
13731373
type = compiler.currentType;
13741374
compiler.currentType = Type.void;
1375-
return module.createStore(type.size >>> 3, arg0, arg1, type.toNativeType());
1375+
return module.createStore(type.byteSize, arg0, arg1, type.toNativeType());
13761376

13771377
case "sizeof": // sizeof<T!>() -> usize
13781378
compiler.currentType = usizeType;

src/compiler.ts

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2217,6 +2217,16 @@ export class Compiler extends DiagnosticEmitter {
22172217
this.error(DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, expression.range, (<Property>element).internalName);
22182218
return this.module.createUnreachable();
22192219

2220+
case ElementKind.FUNCTION_PROTOTYPE:
2221+
if (expression.kind == NodeKind.ELEMENTACCESS) { // @operator("[]")
2222+
assert(resolved.target && resolved.target.kind == ElementKind.CLASS && element.simpleName == (<Class>resolved.target).prototype.fnIndexedGet)
2223+
var resolvedIndexedSet = (<FunctionPrototype>element).resolve(null);
2224+
if (resolvedIndexedSet) {
2225+
elementType = resolvedIndexedSet.returnType;
2226+
break;
2227+
}
2228+
}
2229+
// fall-through
22202230
default:
22212231
this.error(DiagnosticCode.Operation_not_supported, expression.range);
22222232
return this.module.createUnreachable();
@@ -2275,11 +2285,11 @@ export class Compiler extends DiagnosticEmitter {
22752285
this.currentType = tee ? (<Field>element).type : Type.void;
22762286
var elementNativeType = (<Field>element).type.toNativeType();
22772287
if (!tee)
2278-
return this.module.createStore((<Field>element).type.byteSize, targetExpr, valueWithCorrectType, elementNativeType, (<Field>element).memoryOffset);
2288+
return this.module.createStore((<Field>element).type.size >> 3, targetExpr, valueWithCorrectType, elementNativeType, (<Field>element).memoryOffset);
22792289
tempLocal = this.currentFunction.getAndFreeTempLocal((<Field>element).type);
22802290
return this.module.createBlock(null, [ // TODO: simplify if valueWithCorrectType has no side effects
22812291
this.module.createSetLocal(tempLocal.index, valueWithCorrectType),
2282-
this.module.createStore((<Field>element).type.byteSize, targetExpr, this.module.createGetLocal(tempLocal.index, elementNativeType), elementNativeType, (<Field>element).memoryOffset),
2292+
this.module.createStore((<Field>element).type.size >> 3, targetExpr, this.module.createGetLocal(tempLocal.index, elementNativeType), elementNativeType, (<Field>element).memoryOffset),
22832293
this.module.createGetLocal(tempLocal.index, elementNativeType)
22842294
], elementNativeType);
22852295

@@ -2325,6 +2335,38 @@ export class Compiler extends DiagnosticEmitter {
23252335
} else
23262336
this.error(DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, expression.range, (<Property>element).internalName);
23272337
return this.module.createUnreachable();
2338+
2339+
case ElementKind.FUNCTION_PROTOTYPE:
2340+
if (expression.kind == NodeKind.ELEMENTACCESS) { // @operator("[]")
2341+
assert(resolved.target && resolved.target.kind == ElementKind.CLASS);
2342+
var resolvedIndexedGet = (<FunctionPrototype>element).resolve();
2343+
if (!resolvedIndexedGet)
2344+
return this.module.createUnreachable();
2345+
var indexedSetName = (<Class>resolved.target).prototype.fnIndexedSet;
2346+
var indexedSet: Element | null;
2347+
if (indexedSetName != null && (<Class>resolved.target).members && (indexedSet = (<Map<string,Element>>(<Class>resolved.target).members).get(indexedSetName)) && indexedSet.kind == ElementKind.FUNCTION_PROTOTYPE) { // @operator("[]=")
2348+
var resolvedIndexedSet = (<FunctionPrototype>indexedSet).resolve();
2349+
if (!resolvedIndexedSet)
2350+
return this.module.createUnreachable();
2351+
targetExpr = this.compileExpression(<Expression>resolved.targetExpression, this.options.target == Target.WASM64 ? Type.usize64 : Type.usize32, ConversionKind.NONE);
2352+
assert(this.currentType.classType);
2353+
var elementExpr = this.compileExpression((<ElementAccessExpression>expression).elementExpression, Type.i32);
2354+
if (!tee) {
2355+
this.currentType = resolvedIndexedSet.returnType;
2356+
return this.makeCall(resolvedIndexedSet, [ targetExpr, elementExpr, valueWithCorrectType ]);
2357+
}
2358+
this.currentType = resolvedIndexedGet.returnType;
2359+
tempLocal = this.currentFunction.getAndFreeTempLocal(this.currentType);
2360+
return this.module.createBlock(null, [
2361+
this.makeCall(resolvedIndexedSet, [ targetExpr, elementExpr, this.module.createTeeLocal(tempLocal.index, valueWithCorrectType) ]),
2362+
this.module.createGetLocal(tempLocal.index, tempLocal.type.toNativeType()) // TODO: could be different from an actual __get (needs 2 temp locals)
2363+
], this.currentType.toNativeType());
2364+
} else {
2365+
this.error(DiagnosticCode.Index_signature_in_type_0_only_permits_reading, expression.range, (<Class>resolved.target).internalName);
2366+
return this.module.createUnreachable();
2367+
}
2368+
}
2369+
// fall-through
23282370
}
23292371
this.error(DiagnosticCode.Operation_not_supported, expression.range);
23302372
return this.module.createUnreachable();
@@ -2465,8 +2507,11 @@ export class Compiler extends DiagnosticEmitter {
24652507
var resolved = this.program.resolveElementAccess(expression, this.currentFunction); // reports
24662508
if (!resolved)
24672509
return this.module.createUnreachable();
2468-
2469-
throw new Error("not implemented"); // TODO
2510+
assert(resolved.element.kind == ElementKind.FUNCTION_PROTOTYPE && resolved.target && resolved.target.kind == ElementKind.CLASS);
2511+
var instance = (<FunctionPrototype>resolved.element).resolve(null, (<Class>resolved.target).contextualTypeArguments);
2512+
if (!instance)
2513+
return this.module.createUnreachable();
2514+
return this.compileCall(instance, [ expression.expression, expression.elementExpression ], expression);
24702515
}
24712516

24722517
compileIdentifierExpression(expression: IdentifierExpression, contextualType: Type): ExpressionRef {
@@ -2632,7 +2677,7 @@ export class Compiler extends DiagnosticEmitter {
26322677
assert((<Field>element).memoryOffset >= 0);
26332678
targetExpr = this.compileExpression(<Expression>resolved.targetExpression, this.options.target == Target.WASM64 ? Type.usize64 : Type.usize32);
26342679
this.currentType = (<Field>element).type;
2635-
return this.module.createLoad((<Field>element).type.byteSize, (<Field>element).type.is(TypeFlags.SIGNED | TypeFlags.INTEGER),
2680+
return this.module.createLoad((<Field>element).type.size >> 3, (<Field>element).type.is(TypeFlags.SIGNED | TypeFlags.INTEGER),
26362681
targetExpr,
26372682
(<Field>element).type.toNativeType(),
26382683
(<Field>element).memoryOffset

src/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
// internal naming scheme
22

3+
/** Path delimited inserted between file system levels. */
34
export const PATH_DELIMITER = "/";
5+
/** Substitution used to indicate the parent directory. */
46
export const PARENT_SUBST = "..";
7+
/** Function name prefix used for getters. */
58
export const GETTER_PREFIX = "get:";
9+
/** Function name prefix used for setters. */
610
export const SETTER_PREFIX = "set:";
11+
/** Delimiter used between class names and instance members. */
712
export const INSTANCE_DELIMITER = "#";
13+
/** Delimited used between class and namespace names and static members. */
814
export const STATIC_DELIMITER = ".";

src/diagnosticMessages.generated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ export enum DiagnosticCode {
7979
Export_declaration_conflicts_with_exported_declaration_of_0 = 2484,
8080
Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property = 2540,
8181
The_target_of_an_assignment_must_be_a_variable_or_a_property_access = 2541,
82+
Index_signature_in_type_0_only_permits_reading = 2542,
8283
Expected_0_arguments_but_got_1 = 2554,
8384
Expected_at_least_0_arguments_but_got_1 = 2555,
8485
Expected_0_type_arguments_but_got_1 = 2558,
@@ -166,6 +167,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
166167
case 2484: return "Export declaration conflicts with exported declaration of '{0}'.";
167168
case 2540: return "Cannot assign to '{0}' because it is a constant or a read-only property.";
168169
case 2541: return "The target of an assignment must be a variable or a property access.";
170+
case 2542: return "Index signature in type '{0}' only permits reading.";
169171
case 2554: return "Expected {0} arguments, but got {1}.";
170172
case 2555: return "Expected at least {0} arguments, but got {1}.";
171173
case 2558: return "Expected {0} type arguments, but got {1}.";

src/diagnosticMessages.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"Export declaration conflicts with exported declaration of '{0}'.": 2484,
8080
"Cannot assign to '{0}' because it is a constant or a read-only property.": 2540,
8181
"The target of an assignment must be a variable or a property access.": 2541,
82+
"Index signature in type '{0}' only permits reading.": 2542,
8283
"Expected {0} arguments, but got {1}.": 2554,
8384
"Expected at least {0} arguments, but got {1}.": 2555,
8485
"Expected {0} type arguments, but got {1}.": 2558,

src/parser.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,19 @@ export class Parser extends DiagnosticEmitter {
15801580

15811581
var startPos = expr.range.start;
15821582

1583+
// ElementAccessExpression
1584+
if (tn.skip(Token.OPENBRACKET)) {
1585+
next = this.parseExpression(tn); // resets precedence
1586+
if (!next)
1587+
return null;
1588+
if (tn.skip(Token.CLOSEBRACKET))
1589+
expr = Node.createElementAccessExpression(<Expression>expr, <Expression>next, tn.range(startPos, tn.pos));
1590+
else {
1591+
this.error(DiagnosticCode._0_expected, tn.range(), "]");
1592+
return null;
1593+
}
1594+
}
1595+
15831596
// CallExpression
15841597
var typeArguments = this.tryParseTypeArgumentsBeforeArguments(tn); // skips '(' on success
15851598
// there might be better ways to distinguish a LESSTHAN from a CALL with type arguments
@@ -1593,7 +1606,6 @@ export class Parser extends DiagnosticEmitter {
15931606
var token: Token;
15941607
var next: Expression | null = null;
15951608
var nextPrecedence: Precedence;
1596-
15971609
while ((nextPrecedence = determinePrecedence(token = tn.peek())) >= precedence) { // precedence climbing
15981610
tn.next();
15991611

@@ -1604,19 +1616,6 @@ export class Parser extends DiagnosticEmitter {
16041616
return null;
16051617
expr = Node.createAssertionExpression(AssertionKind.AS, expr, toType, tn.range(startPos, tn.pos));
16061618

1607-
// ElementAccessExpression
1608-
} else if (token == Token.OPENBRACKET) {
1609-
next = this.parseExpression(tn); // resets precedence
1610-
if (!next)
1611-
return null;
1612-
1613-
if (tn.skip(Token.CLOSEBRACKET))
1614-
expr = Node.createElementAccessExpression(<Expression>expr, <Expression>next, tn.range(startPos, tn.pos));
1615-
else {
1616-
this.error(DiagnosticCode._0_expected, tn.range(), "]");
1617-
return null;
1618-
}
1619-
16201619
// UnaryPostfixExpression
16211620
} else if (token == Token.PLUS_PLUS || token == Token.MINUS_MINUS) {
16221621
if (expr.kind != NodeKind.IDENTIFIER && expr.kind != NodeKind.ELEMENTACCESS && expr.kind != NodeKind.PROPERTYACCESS)

0 commit comments

Comments
 (0)