diff --git a/apps/parser/generated/cst-types.ts b/apps/parser/generated/cst-types.ts index 89c0d6c..eb62d55 100644 --- a/apps/parser/generated/cst-types.ts +++ b/apps/parser/generated/cst-types.ts @@ -76,13 +76,35 @@ export interface ExpressionCstNode extends CstNode { } export type ExpressionCstChildren = { - value: ValueCstNode[]; + chainValue: ChainValueCstNode[]; PostFix?: IToken[]; CmpAsgn?: IToken[]; BinOp?: IToken[]; expression?: ExpressionCstNode[]; }; +export interface ChainValueCstNode extends CstNode { + name: 'chainValue'; + children: ChainValueCstChildren; +} + +export type ChainValueCstChildren = { + value: ValueCstNode[]; + indexOrSlice?: IndexOrSliceCstNode[]; +}; + +export interface IndexOrSliceCstNode extends CstNode { + name: 'indexOrSlice'; + children: IndexOrSliceCstChildren; +} + +export type IndexOrSliceCstChildren = { + LBRACK: IToken[]; + expression?: ExpressionCstNode[]; + COLON?: IToken[]; + RBRACK: IToken[]; +}; + export interface ValueCstNode extends CstNode { name: 'value'; children: ValueCstChildren; @@ -90,7 +112,7 @@ export interface ValueCstNode extends CstNode { export type ValueCstChildren = { UnOp?: IToken[]; - value?: ValueCstNode[]; + chainValue?: ChainValueCstNode[]; constant?: ConstantCstNode[]; ID?: IToken[]; LPAREN?: IToken[]; @@ -107,9 +129,13 @@ export type ConstantCstChildren = { STRING?: IToken[]; BOOL?: IToken[]; BIN?: IToken[]; - INT?: IToken[]; CMPX?: IToken[]; REAL?: IToken[]; + INT?: IToken[]; + LBRACK?: IToken[]; + expression?: ExpressionCstNode[]; + COMMA?: IToken[]; + RBRACK?: IToken[]; }; export interface TypeCstNode extends CstNode { @@ -119,6 +145,18 @@ export interface TypeCstNode extends CstNode { export type TypeCstChildren = { BASIC_TYPE: IToken[]; + arrayType?: ArrayTypeCstNode[]; +}; + +export interface ArrayTypeCstNode extends CstNode { + name: 'arrayType'; + children: ArrayTypeCstChildren; +} + +export type ArrayTypeCstChildren = { + LBRACK: IToken[]; + INT?: IToken[]; + RBRACK: IToken[]; }; export interface ICstNodeVisitor extends ICstVisitor { @@ -128,7 +166,10 @@ export interface ICstNodeVisitor extends ICstVisitor { body(children: BodyCstChildren, param?: IN): OUT; declaration(children: DeclarationCstChildren, param?: IN): OUT; expression(children: ExpressionCstChildren, param?: IN): OUT; + chainValue(children: ChainValueCstChildren, param?: IN): OUT; + indexOrSlice(children: IndexOrSliceCstChildren, param?: IN): OUT; value(children: ValueCstChildren, param?: IN): OUT; constant(children: ConstantCstChildren, param?: IN): OUT; type(children: TypeCstChildren, param?: IN): OUT; + arrayType(children: ArrayTypeCstChildren, param?: IN): OUT; } diff --git a/apps/parser/generated/syntax-diagrams.html b/apps/parser/generated/syntax-diagrams.html index 111d915..1936af5 100644 --- a/apps/parser/generated/syntax-diagrams.html +++ b/apps/parser/generated/syntax-diagrams.html @@ -1,694 +1,873 @@ + - - - - - + + + + + + -
+
diff --git a/apps/parser/main.ts b/apps/parser/main.ts index b4a0f94..97f2631 100644 --- a/apps/parser/main.ts +++ b/apps/parser/main.ts @@ -37,6 +37,9 @@ export async function main(): Promise { const lexingResult = CalvinLexer.tokenize(inputFile); // "input" is a setter which will reset the parser's state. parser.input = lexingResult.tokens; + + const output = parser.file(); + if (parser.errors.length > 0) { throw new AggregateError( parser.errors, @@ -44,8 +47,6 @@ export async function main(): Promise { ); } - const output = parser.file(); - printer.visit(output); } diff --git a/apps/parser/src/lexer.ts b/apps/parser/src/lexer.ts index c35268e..067d2a4 100644 --- a/apps/parser/src/lexer.ts +++ b/apps/parser/src/lexer.ts @@ -210,8 +210,11 @@ export const LPAREN: TokenType = createToken({ name: 'LPAREN', pattern: '(' }); export const RPAREN: TokenType = createToken({ name: 'RPAREN', pattern: ')' }); export const LCURLY: TokenType = createToken({ name: 'LCURLY', pattern: '{' }); export const RCURLY: TokenType = createToken({ name: 'RCURLY', pattern: '}' }); +export const LBRACK: TokenType = createToken({ name: 'LBRACK', pattern: '[' }); +export const RBRACK: TokenType = createToken({ name: 'RBRACK', pattern: ']' }); export const SEMI: TokenType = createToken({ name: 'SEMI', pattern: ';' }); export const COLON: TokenType = createToken({ name: 'COLON', pattern: ':' }); +export const COMMA: TokenType = createToken({ name: 'COMMA', pattern: ',' }); /* Keywords */ export const LET: TokenType = createToken({ name: 'LET', pattern: 'let', longer_alt: ID }); // Selection @@ -269,8 +272,11 @@ export const allTokens: TokenType[] = [ RPAREN, LCURLY, RCURLY, + LBRACK, + RBRACK, SEMI, COLON, + COMMA, ERROR, ]; diff --git a/apps/parser/src/parser.ts b/apps/parser/src/parser.ts index 787c42c..3e72d9e 100644 --- a/apps/parser/src/parser.ts +++ b/apps/parser/src/parser.ts @@ -129,7 +129,7 @@ export class CalvinParser extends CstParser { }); private expression = this.RULE('expression', () => { - this.SUBRULE(this.value); + this.SUBRULE(this.chainValue); this.OR([ { ALT: () => this.CONSUME(Tokens.PostFix), @@ -153,12 +153,36 @@ export class CalvinParser extends CstParser { ]); }); + private chainValue = this.RULE('chainValue', () => { + this.SUBRULE(this.value); + this.MANY(() => { + this.SUBRULE(this.indexOrSlice); + }); + }); + + private indexOrSlice = this.RULE('indexOrSlice', () => { + this.CONSUME(Tokens.LBRACK); + // This allows for expressions of the form arr[] to be syntactically valid + // I don't like it, but I guess this can be handled on the semantic level??? + // This was the best way I could fix the common lookahead prefix error + this.OPTION(() => this.SUBRULE(this.expression)); + this.OPTION1(() => { + this.CONSUME(Tokens.COLON); + this.OPTION2(() => this.SUBRULE1(this.expression)); + this.OPTION3(() => { + this.CONSUME1(Tokens.COLON); + this.SUBRULE2(this.expression); + }); + }); + this.CONSUME(Tokens.RBRACK); + }); + private value = this.RULE('value', () => { this.OR([ { ALT: () => { this.CONSUME(Tokens.UnOp); - this.SUBRULE1(this.value); + this.SUBRULE1(this.chainValue); }, }, { @@ -178,10 +202,33 @@ export class CalvinParser extends CstParser { }); private constant = this.RULE('constant', () => - this.OR(Tokens.literals.map((t) => ({ ALT: () => this.CONSUME(t) }))), + this.OR([ + ...Tokens.literals.map((t) => ({ ALT: () => this.CONSUME(t) })), + { + ALT: () => { + this.CONSUME(Tokens.LBRACK); + this.MANY_SEP({ + SEP: Tokens.COMMA, + DEF: () => this.SUBRULE(this.expression), + }); + this.CONSUME(Tokens.RBRACK); + }, + }, + ]), ); - private type = this.RULE('type', () => this.CONSUME(Tokens.BASIC_TYPE)); + private type = this.RULE('type', () => { + this.CONSUME(Tokens.BASIC_TYPE); + this.MANY(() => { + this.SUBRULE(this.arrayType); + }); + }); + + private arrayType = this.RULE('arrayType', () => { + this.CONSUME(Tokens.LBRACK); + this.OPTION(() => this.CONSUME(Tokens.INT)); + this.CONSUME(Tokens.RBRACK); + }); } export const parser: CalvinParser = new CalvinParser(); diff --git a/apps/parser/src/visitors/precedence.ts b/apps/parser/src/visitors/precedence.ts index 77701a2..7a973e2 100644 --- a/apps/parser/src/visitors/precedence.ts +++ b/apps/parser/src/visitors/precedence.ts @@ -1,17 +1,20 @@ import type { CstNode, TokenType } from 'chevrotain'; import type { + ArrayTypeCstChildren, BodyCstChildren, + ChainValueCstChildren, + ChainValueCstNode, ConstantCstChildren, DeclarationCstChildren, ExpressionCstChildren, ExpressionCstNode, FileCstChildren, IfPredBodyCstChildren, + IndexOrSliceCstChildren, StatementCstChildren, StatementCstNode, TypeCstChildren, ValueCstChildren, - ValueCstNode, } from '@/generated/cst-types.ts'; import * as Tokens from '../lexer.ts'; import { BaseCstVisitor } from '../parser.ts'; @@ -94,19 +97,26 @@ export class PrecedenceHandler extends BaseCstVisitor { // tree is now tree.right tree = { ...right }; // old tree.right is now tree.right.left - const left = tree.value[0]; + const left = tree.chainValue[0]; old.expression = [ { ...left, - children: { value: [{ ...left }] }, + children: { chainValue: [{ ...left }] }, name: 'expression', } satisfies ExpressionCstNode, ]; // new tree.left is now old tree - tree.value[0] = { - children: { expression: [{ name: 'expression', children: old }] }, - name: 'value', - } satisfies ValueCstNode; + tree.chainValue[0] = { + children: { + value: [ + { + name: 'value', + children: { expression: [{ name: 'expression', children: old }] }, + }, + ], + }, + name: 'chainValue', + } satisfies ChainValueCstNode; } } } @@ -115,16 +125,61 @@ export class PrecedenceHandler extends BaseCstVisitor { expression(expr: ExpressionCstNode) { expr.children = this.reorder(expr.children); - this.value(expr.children.value[0].children); + this.chainValue(expr.children.chainValue[0].children); + } + + chainValue(cval: ChainValueCstChildren) { + this.value(cval.value[0].children); + if (cval.indexOrSlice) { + cval.indexOrSlice.forEach((ios) => { + this.indexOrSlice(ios.children); + }); + } + } + + indexOrSlice(ios: IndexOrSliceCstChildren) { + if (ios.LBRACK && ios.RBRACK) { + if (ios.COLON) { + let exprCount = 0; + if (ios.expression?.at(exprCount)) { + // start + this.expression(ios.expression[exprCount++]); + } + if (ios.expression?.at(exprCount)) { + // end + this.expression(ios.expression[exprCount++]); + } + if (ios.COLON.at(1)) { + if (ios.expression?.at(exprCount)) { + // direction + this.expression(ios.expression[exprCount++]); + } + } + } else if (ios.expression?.at(0)) { + this.expression(ios.expression[0]); + } + } } value(val: ValueCstChildren) { if (val.expression) { // nested expression this.expression(val.expression[0]); - } else if (!val.constant && !val.ID && val.value) { + } else if (val.constant) { + // possible array literal + this.constant(val.constant[0].children); + } else if (!val.ID && val.chainValue) { // Unop - this.value(val.value[0].children); + this.chainValue(val.chainValue[0].children); + } + } + + constant(c: ConstantCstChildren) { + if (c.expression) { + // list + c.expression.forEach((e) => { + this.expression(e); + }); } } @@ -199,10 +254,10 @@ export class PrecedenceHandler extends BaseCstVisitor { } } - constant(_c: ConstantCstChildren) {} - type(_t: TypeCstChildren) {} + arrayType(_at: ArrayTypeCstChildren) {} + override visit(node: CstNode) { switch (node.name) { case 'file': @@ -223,6 +278,12 @@ export class PrecedenceHandler extends BaseCstVisitor { case 'expression': this.expression(node as ExpressionCstNode); break; + case 'chainValue': + this.chainValue(node.children as ChainValueCstChildren); + break; + case 'indexOrSlice': + this.indexOrSlice(node.children as IndexOrSliceCstChildren); + break; case 'value': this.value(node.children as ValueCstChildren); break; @@ -232,6 +293,9 @@ export class PrecedenceHandler extends BaseCstVisitor { case 'type': this.type(node.children as TypeCstChildren); break; + case 'arrayType': + this.arrayType(node.children as ArrayTypeCstChildren); + break; } } } diff --git a/apps/parser/src/visitors/printer.ts b/apps/parser/src/visitors/printer.ts index 109e687..61d6d4f 100644 --- a/apps/parser/src/visitors/printer.ts +++ b/apps/parser/src/visitors/printer.ts @@ -1,12 +1,15 @@ import type { CstNode, IToken } from 'chevrotain'; import type { + ArrayTypeCstChildren, BodyCstChildren, + ChainValueCstChildren, ConstantCstChildren, DeclarationCstChildren, ExpressionCstChildren, FileCstChildren, ICstNodeVisitor, IfPredBodyCstChildren, + IndexOrSliceCstChildren, StatementCstChildren, StatementCstNode, TypeCstChildren, @@ -131,13 +134,50 @@ export class CalvinPrinter extends BaseCstVisitor implements ICstNodeVisitor { + this.indexOrSlice(ios.children, indent); + }); + } + } + + indexOrSlice(ios: IndexOrSliceCstChildren, indent: number) { + if (ios.LBRACK && ios.RBRACK) { + tree('[', indent); + if (ios.COLON) { + let exprCount = 0; + if (ios.expression?.at(exprCount)) { + // start + this.expression(ios.expression[exprCount++].children, indent + 2); + } + tree(':', indent); + if (ios.expression?.at(exprCount)) { + // end + this.expression(ios.expression[exprCount++].children, indent + 2); + } + if (ios.COLON.at(1)) { + tree(':', indent); + if (ios.expression?.at(exprCount)) { + // direction + this.expression(ios.expression[exprCount++].children, indent + 2); + } + } + } else if (ios.expression?.at(0)) { + this.expression(ios.expression[0].children, indent + 2); + } + tree(']', indent); + } + } + value(val: ValueCstChildren, indent: number) { if (val.expression) { tree('(', indent); @@ -147,10 +187,10 @@ export class CalvinPrinter extends BaseCstVisitor implements ICstNodeVisitor 'tokenType' in v[0]) as IToken[]; tree(`(${op[0].image}!`, indent); - this.value(val.value[0].children, indent + 2); + this.chainValue(val.chainValue[0].children, indent + 2); tree(`)`, indent); } else { throw new Error(`TypeInference: unhandled value type ${JSON.stringify(val)}`); @@ -158,11 +198,32 @@ export class CalvinPrinter extends BaseCstVisitor implements ICstNodeVisitor { + this.expression(e.children, indent + 2); + }); + tree(']', indent); + } else if (c.LBRACK) { + // empty list + tree('[]', indent); + } else { + tree((Object.values(c)[0][0] as IToken).image, indent); + } } type(t: TypeCstChildren, indent: number) { tree(`: ${t.BASIC_TYPE[0].image}`, indent); + if (t.arrayType) { + t.arrayType.forEach((at) => { + this.arrayType(at.children, indent + 2); + }); + } + } + + arrayType(a: ArrayTypeCstChildren, indent: number) { + tree(`[${a.INT?.at(0)?.image ?? ''}]`, indent); } override visit(node: CstNode, indent: number = 0) { @@ -185,6 +246,12 @@ export class CalvinPrinter extends BaseCstVisitor implements ICstNodeVisitor; + type?: never; + size?: never; + }; + +export function printType(t: Type): string { + switch (t.class) { + case TypeClass.Unknown: return 'unknown'; - case TypeClasses.Integral: + case TypeClass.Integral: return 'integer'; - case TypeClasses.Real: + case TypeClass.Real: return 'real'; - case TypeClasses.Complex: + case TypeClass.Complex: return 'complex'; - case TypeClasses.Boolean: + case TypeClass.Boolean: return 'boolean'; - case TypeClasses.Binary: + case TypeClass.Binary: return 'binary'; - case TypeClasses.String: + case TypeClass.String: return 'string'; - case TypeClasses.Never: + case TypeClass.Container: + return `${printType(t.type)}[${t.size ?? '?'}]`; + case TypeClass.Never: return 'never'; } } +export function compareType(a: Type, b: Type): boolean { + if (a.class === TypeClass.Container && b.class === TypeClass.Container) { + return a.size === b.size && compareType(a.type, b.type); + } else { + return a.class === b.class; + } +} + export type Meta = { - returnType: TypeClasses; + returnType: Type; source: IToken; }; @@ -144,7 +170,7 @@ export class Scope { export class CalvinTypeAnalyzer extends BaseCstVisitor - implements ICstNodeVisitor + implements ICstNodeVisitor { private counts; private _errors; @@ -230,6 +256,12 @@ export class CalvinTypeAnalyzer case 'expression': this.expression(node.children as ExpressionCstChildren); break; + case 'chainValue': + this.chainValue(node.children as ChainValueCstChildren); + break; + case 'indexOrSlice': + this.indexOrSlice(node.children as IndexOrSliceCstChildren); + break; case 'value': this.value(node.children as ValueCstChildren); break; @@ -239,6 +271,9 @@ export class CalvinTypeAnalyzer case 'type': this.type(node.children as TypeCstChildren); break; + case 'arrayType': + this.arrayType(node.children as ArrayTypeCstChildren); + break; } } @@ -319,7 +354,8 @@ export class CalvinTypeAnalyzer const id = decl.ID[0]; const t = decl.type ? this.type(decl.type[0].children) : null; const expr = decl.expression ? this.expression(decl.expression[0].children) : null; - const meta = t ?? expr ?? ({ source: id, returnType: TypeClasses.Unknown } satisfies Meta); + const meta = + t ?? expr ?? ({ source: id, returnType: { class: TypeClass.Unknown } } satisfies Meta); const search = this.scope.search(id.image); const existing = this.scope === search?.scope && search.found; if (search) { @@ -334,7 +370,7 @@ export class CalvinTypeAnalyzer } } if (t && expr) { - if (t.returnType !== expr.returnType) { + if (!compareType(t.returnType, expr.returnType)) { // TODO type resolution algorithm this.error( `type declaration on line ${t.source.startLine} does not match assignment on line ${expr.source.startLine}`, @@ -361,12 +397,62 @@ export class CalvinTypeAnalyzer if (op) { // TODO value operator mismatch } - const val = this.value(expr.value[0].children); + const val = this.chainValue(expr.chainValue[0].children); // TODO handle type mismatch const exprMeta = expr.expression ? this.expression(expr.expression[0].children) : null; return exprMeta ?? val; } + chainValue(cval: ChainValueCstChildren): Meta { + const val = this.value(cval.value[0].children); + if (cval.indexOrSlice) { + return cval.indexOrSlice.reduce((val: Meta, ios) => { + this.indexOrSlice(ios.children); + const isSlice = !!ios.children.COLON; + if (val.returnType.class === TypeClass.Container) { + if (isSlice) { + val.source = ios.children.LBRACK[0]; + return val; + } else { + return { source: ios.children.LBRACK[0], returnType: val.returnType.type }; + } + } else { + this.error(`Bad array indexing at ${val.source.image} on line ${val.source.startLine}!`); + return { + source: ios.children.LBRACK[0], + returnType: { class: TypeClass.Never }, + } satisfies Meta; + } + }, val); + } else { + return val; + } + } + + indexOrSlice(ios: IndexOrSliceCstChildren): undefined { + if (ios.LBRACK && ios.RBRACK) { + if (ios.COLON) { + let exprCount = 0; + if (ios.expression?.at(exprCount)) { + // start + this.expression(ios.expression[exprCount++].children); + } + if (ios.expression?.at(exprCount)) { + // end + this.expression(ios.expression[exprCount++].children); + } + if (ios.COLON.at(1)) { + if (ios.expression?.at(exprCount)) { + // direction + this.expression(ios.expression[exprCount++].children); + } + } + } else if (ios.expression?.at(0)) { + this.expression(ios.expression[0].children); + } + } + } + value(val: ValueCstChildren): Meta { if (val.expression) { return this.expression(val.expression[0].children); @@ -380,47 +466,80 @@ export class CalvinTypeAnalyzer } const meta = existing?.found?.meta; - return meta ?? ({ source: id, returnType: TypeClasses.Never } satisfies Meta); - } else if (val.value) { + return meta ?? ({ source: id, returnType: { class: TypeClass.Never } } satisfies Meta); + } else if (val.chainValue) { //const op = Object.values(val).find((v) => 'tokenType' in v[0]) as IToken[]; // TODO value operator mismatch - return this.value(val.value[0].children); + return this.chainValue(val.chainValue[0].children); } throw new Error(`TypeInference: unhandled value type ${JSON.stringify(val)}`); } constant(c: ConstantCstChildren): Meta { - if (c.BIN) return { source: c.BIN[0], returnType: TypeClasses.Binary }; - else if (c.BOOL) return { source: c.BOOL[0], returnType: TypeClasses.Boolean }; - else if (c.CMPX) return { source: c.CMPX[0], returnType: TypeClasses.Complex }; - else if (c.REAL) return { source: c.REAL[0], returnType: TypeClasses.Real }; - else if (c.INT) return { source: c.INT[0], returnType: TypeClasses.Integral }; - else if (c.STRING) return { source: c.STRING[0], returnType: TypeClasses.String }; + if (c.BIN) return { source: c.BIN[0], returnType: { class: TypeClass.Binary } }; + else if (c.BOOL) return { source: c.BOOL[0], returnType: { class: TypeClass.Boolean } }; + else if (c.CMPX) return { source: c.CMPX[0], returnType: { class: TypeClass.Complex } }; + else if (c.REAL) return { source: c.REAL[0], returnType: { class: TypeClass.Real } }; + else if (c.INT) return { source: c.INT[0], returnType: { class: TypeClass.Integral } }; + else if (c.STRING) return { source: c.STRING[0], returnType: { class: TypeClass.String } }; + else if (c.LBRACK && c.expression) { + // TODO handle type mismatch + return { + source: c.LBRACK[0], + returnType: { + class: TypeClass.Container, + type: this.expression(c.expression[0].children).returnType, + size: c.expression.length, + }, + }; + } else if (c.LBRACK) + return { + source: c.LBRACK[0], + returnType: { class: TypeClass.Container, type: { class: TypeClass.Unknown }, size: 0 }, + }; // this should never be reached, except maybe when adding a new literal type throw new Error(`Could not get type from constant token ${JSON.stringify(c, null, 4)}`); } type(t: TypeCstChildren): Meta { const source = t.BASIC_TYPE[0]; - return { - source, - returnType: [source.image].map((t) => { + const tClass = { + class: [source.image].map((t) => { switch (t[0]) { case 'i': case 'u': - return TypeClasses.Integral; + return TypeClass.Integral; case 'x': - return TypeClasses.Complex; + return TypeClass.Complex; case 'r': - return TypeClasses.Real; + return TypeClass.Real; case 'b': - return t[1] === 'o' ? TypeClasses.Boolean : TypeClasses.Binary; + return t[1] === 'o' ? TypeClass.Boolean : TypeClass.Binary; case 's': - return TypeClasses.String; + return TypeClass.String; default: - return TypeClasses.Unknown; + return TypeClass.Unknown; } })[0], + } satisfies Type; + return { + source, + returnType: + t.arrayType?.reduce((p: Type, c) => ({ ...this.arrayType(c.children), type: p }), tClass) ?? + tClass, + }; + } + + arrayType(a: ArrayTypeCstChildren): { + class: TypeClass.Container; + type: Type; + size: number | null; + } { + const size = parseInt(a.INT?.at(0)?.image ?? 'NaN', 10); + return { + class: TypeClass.Container, + type: { class: TypeClass.Unknown }, + size: Number.isNaN(size) ? null : size, }; } } diff --git a/apps/parser/test/end-to-end/fixtures/arrays.txt b/apps/parser/test/end-to-end/fixtures/arrays.txt new file mode 100644 index 0000000..f6bb36d --- /dev/null +++ b/apps/parser/test/end-to-end/fixtures/arrays.txt @@ -0,0 +1,9 @@ +let arr = [1, 2]; +let empty: i32[] = []; // otherwise type is unknown[] +let sliced = arr[1:2]; +let indexed = arr[0 + 1 - 1]; +let indexOfSliced = sliced[0]; +let check = indexed == indexOfSliced; +let multi: i32[2][] = [[1, 2], [3, 4]]; +let badMulti = [[1, 2], 3]; // should have semantic error +let badIndex = arr[1][1]; \ No newline at end of file diff --git a/apps/parser/yacc-reference/lex.l b/apps/parser/yacc-reference/lex.l index d8eb686..605269d 100644 --- a/apps/parser/yacc-reference/lex.l +++ b/apps/parser/yacc-reference/lex.l @@ -165,15 +165,15 @@ using return yy::parser::make_USING (loc); "}" return yy::parser::make_RBRACE (loc); // DONE "(" return yy::parser::make_LPAREN (loc); // DONE ")" return yy::parser::make_RPAREN (loc); // DONE -"[" return yy::parser::make_LBRACK (loc); -"]" return yy::parser::make_RBRACK (loc); +"[" return yy::parser::make_LBRACK (loc); // DONE +"]" return yy::parser::make_RBRACK (loc); // DONE ";" return yy::parser::make_SEMI (loc); // DONE "_" return yy::parser::make_USCORE (loc); "?" return yy::parser::make_QUE (loc); "!" return yy::parser::make_BANG (loc); ":" return yy::parser::make_COLON (loc); // DONE "??" return yy::parser::make_N_COAL (loc); // DONE -"," return yy::parser::make_COMMA (loc); +"," return yy::parser::make_COMMA (loc); // DONE "." return yy::parser::make_DOT (loc); . { throw yy::parser::syntax_error(loc, "invalid character: " + std::string(yytext));} <> return yy::parser::make_YYEOF (loc); diff --git a/apps/parser/yacc-reference/parser.y b/apps/parser/yacc-reference/parser.y index 14905ec..697d43c 100644 --- a/apps/parser/yacc-reference/parser.y +++ b/apps/parser/yacc-reference/parser.y @@ -369,7 +369,7 @@ compound_assign: // DONE | value RS_EQU expression | value AS_EQU expression | value NC_EQU expression; -value: // 2/15 +value: // 5/15 constant // DONE | ID // DONE | GLOBAL ID @@ -380,10 +380,10 @@ value: // 2/15 | function_call | value optional_chain DOT ID | value optional_chain DOT function_call - | value optional_chain LBRACK expression RBRACK - | value optional_chain LBRACK slice RBRACK + | value optional_chain LBRACK expression RBRACK // DONE + | value optional_chain LBRACK slice RBRACK // DONE | LBRACE list_expression RBRACE - | LPAREN expression RPAREN + | LPAREN expression RPAREN // DONE | type_signature LPAREN expression RPAREN; constant: // DONE BOOL { debug::log(drv.trace_parsing) << std::endl << "Parser push boolean: " << $1 << std::endl << std::endl; } @@ -398,7 +398,7 @@ optional_chain: QUE | BANG |; -slice: +slice: // DONE optional_expression COLON optional_expression | optional_expression COLON optional_expression COLON expression;