diff --git a/src/compiler/compiler.ts b/src/compiler/compiler.ts index be939cf..429a94b 100644 --- a/src/compiler/compiler.ts +++ b/src/compiler/compiler.ts @@ -75,6 +75,7 @@ export class Compiler { if (DEBUG) { const bytecodeString = bytecodeToString(this.bytecode) console.log(`\n🤖 bytecode:\n----------------\n${bytecodeString}\n\n`) + console.log(`\n🤖 bytecode:\n----------------\n${this.instructions}\n\n`) } } catch (error) { if (error instanceof CompilerError) { @@ -281,13 +282,27 @@ export class Compiler { const opValue = input.slice(operator.from, operator.to) switch (opValue) { - case '+=': instructions.push(['ADD']); break - case '-=': instructions.push(['SUB']); break - case '*=': instructions.push(['MUL']); break - case '/=': instructions.push(['DIV']); break - case '%=': instructions.push(['MOD']); break + case '+=': + instructions.push(['ADD']) + break + case '-=': + instructions.push(['SUB']) + break + case '*=': + instructions.push(['MUL']) + break + case '/=': + instructions.push(['DIV']) + break + case '%=': + instructions.push(['MOD']) + break default: - throw new CompilerError(`Unknown compound operator: ${opValue}`, operator.from, operator.to) + throw new CompilerError( + `Unknown compound operator: ${opValue}`, + operator.from, + operator.to + ) } // DUP and store (same as regular assignment) @@ -305,10 +320,8 @@ export class Compiler { } case terms.FunctionDef: { - const { paramNames, bodyNodes, catchVariable, catchBody, finallyBody } = getFunctionDefParts( - node, - input - ) + const { paramNames, bodyNodes, catchVariable, catchBody, finallyBody } = + getFunctionDefParts(node, input) const instructions: ProgramItem[] = [] const functionLabel: Label = `.func_${this.fnLabelCount++}` const afterLabel: Label = `.after_${functionLabel}` @@ -331,7 +344,13 @@ export class Compiler { if (catchVariable || finallyBody) { // If function has catch or finally, wrap body in try/catch/finally instructions.push( - ...this.#compileTryCatchFinally(compileFunctionBody, catchVariable, catchBody, finallyBody, input) + ...this.#compileTryCatchFinally( + compileFunctionBody, + catchVariable, + catchBody, + finallyBody, + input + ) ) } else { instructions.push(...compileFunctionBody()) @@ -414,8 +433,9 @@ export class Compiler { instructions.push(['JUMP', afterLabel]) instructions.push([`${fnLabel}:`]) instructions.push( - ...block.filter(x => x.type.name !== 'keyword') - .map(x => this.#compileNode(x!, input)) + ...block + .filter((x) => x.type.name !== 'keyword') + .map((x) => this.#compileNode(x!, input)) .flat() ) instructions.push(['RETURN']) @@ -435,15 +455,16 @@ export class Compiler { body = [ ...body.slice(0, startSlice), ['MAKE_FUNCTION', [], fnLabel], - ...body.slice(startSlice) + ...body.slice(startSlice), ] // @ts-ignore body[body.length - 3]![1] += 1 instructions.push(...body) - } else { - throw new Error(`FunctionCallWithBlock: Expected FunctionCallOrIdentifier or FunctionCall`) + throw new Error( + `FunctionCallWithBlock: Expected FunctionCallOrIdentifier or FunctionCall` + ) } return instructions @@ -642,7 +663,7 @@ export class Compiler { // = can be a valid word, and is also valid inside words, so for now we cheat // and check for arrays that look like `[ = ]` to interpret them as // empty dicts - if (children.length === 1 && children[0]!.name === 'Word') { + if (children.length === 1 && children[0]!.type.id === terms.Word) { const child = children[0]! if (input.slice(child.from, child.to) === '=') { return [['MAKE_DICT', 0]] @@ -691,6 +712,10 @@ export class Compiler { return instructions } + case terms.Comment: { + return [] // ignore comments + } + default: throw new CompilerError( `Compiler doesn't know how to handle a "${node.type.name}" node.`, diff --git a/src/compiler/tests/compiler.test.ts b/src/compiler/tests/compiler.test.ts index 743f738..ad62392 100644 --- a/src/compiler/tests/compiler.test.ts +++ b/src/compiler/tests/compiler.test.ts @@ -304,9 +304,12 @@ describe('default params', () => { }) test.skip('dict default', () => { - expect('make-person = do person=[name=Bob age=60]: person end; make-person') - .toEvaluateTo({ name: 'Bob', age: 60 }) - expect('make-person = do person=[name=Bob age=60]: person end; make-person [name=Jon age=21]') - .toEvaluateTo({ name: 'Jon', age: 21 }) + expect('make-person = do person=[name=Bob age=60]: person end; make-person').toEvaluateTo({ + name: 'Bob', + age: 60, + }) + expect( + 'make-person = do person=[name=Bob age=60]: person end; make-person [name=Jon age=21]' + ).toEvaluateTo({ name: 'Jon', age: 21 }) }) -}) \ No newline at end of file +}) diff --git a/src/compiler/tests/literals.test.ts b/src/compiler/tests/literals.test.ts index 666a4b5..c1dc14b 100644 --- a/src/compiler/tests/literals.test.ts +++ b/src/compiler/tests/literals.test.ts @@ -66,8 +66,8 @@ describe('array literals', () => { }) test('comments within arrays', () => { - expect(`[1 # first - 2 # second + expect(`[1 + 2 ]`).toEvaluateTo([1, 2]) }) diff --git a/src/compiler/utils.ts b/src/compiler/utils.ts index ed0dfcc..20afa96 100644 --- a/src/compiler/utils.ts +++ b/src/compiler/utils.ts @@ -22,7 +22,8 @@ export const getAllChildren = (node: SyntaxNode): SyntaxNode[] => { children.push(child) child = child.nextSibling } - return children + + return children.filter((n) => n.type.id !== terms.Comment) } export const getBinaryParts = (node: SyntaxNode) => { @@ -50,13 +51,15 @@ export const getAssignmentParts = (node: SyntaxNode) => { // array destructuring if (left && left.type.id === terms.Array) { - const identifiers = getAllChildren(left).filter(child => child.type.id === terms.Identifier) + const identifiers = getAllChildren(left).filter((child) => child.type.id === terms.Identifier) return { arrayPattern: identifiers, right } } if (!left || left.type.id !== terms.AssignableIdentifier) { throw new CompilerError( - `Assign left child must be an AssignableIdentifier or Array, got ${left ? left.type.name : 'none'}`, + `Assign left child must be an AssignableIdentifier or Array, got ${ + left ? left.type.name : 'none' + }`, node.from, node.to ) @@ -71,7 +74,9 @@ export const getCompoundAssignmentParts = (node: SyntaxNode) => { if (!left || left.type.id !== terms.AssignableIdentifier) { throw new CompilerError( - `CompoundAssign left child must be an AssignableIdentifier, got ${left ? left.type.name : 'none'}`, + `CompoundAssign left child must be an AssignableIdentifier, got ${ + left ? left.type.name : 'none' + }`, node.from, node.to ) diff --git a/src/parser/shrimp.grammar b/src/parser/shrimp.grammar index 64c44df..e9bc2ec 100644 --- a/src/parser/shrimp.grammar +++ b/src/parser/shrimp.grammar @@ -2,7 +2,7 @@ @context trackScope from "./scopeTracker" -@skip { space | comment } +@skip { space | Comment } @top Program { item* } @@ -18,7 +18,7 @@ newlineOrSemicolon { "\n" | ";" } eof { @eof } space { " " | "\t" } - comment { "#" ![\n]* } + Comment { "#" " " ![\n]* } leftParen { "(" } rightParen { ")" } colon[closedBy="end", @name="colon"] { ":" } diff --git a/src/parser/shrimp.terms.ts b/src/parser/shrimp.terms.ts index 568b4af..716ef1c 100644 --- a/src/parser/shrimp.terms.ts +++ b/src/parser/shrimp.terms.ts @@ -24,42 +24,43 @@ export const Word = 22, IdentifierBeforeDot = 23, Do = 24, - Program = 25, - PipeExpr = 26, - FunctionCall = 27, - DotGet = 28, - Number = 29, - ParenExpr = 30, - IfExpr = 31, - keyword = 69, - ConditionalOp = 33, - String = 34, - StringFragment = 35, - Interpolation = 36, - EscapeSeq = 37, - Boolean = 38, - Regex = 39, - Dict = 40, - NamedArg = 41, - NamedArgPrefix = 42, - FunctionDef = 43, - Params = 44, - NamedParam = 45, - Null = 46, - colon = 47, - CatchExpr = 48, - Block = 50, - FinallyExpr = 51, - Underscore = 54, - Array = 55, - ElseIfExpr = 56, - ElseExpr = 58, - FunctionCallOrIdentifier = 59, - BinOp = 60, - PositionalArg = 61, - WhileExpr = 63, - FunctionCallWithBlock = 65, - TryExpr = 66, - Throw = 68, - CompoundAssign = 70, - Assign = 71 + Comment = 25, + Program = 26, + PipeExpr = 27, + FunctionCall = 28, + DotGet = 29, + Number = 30, + ParenExpr = 31, + IfExpr = 32, + keyword = 70, + ConditionalOp = 34, + String = 35, + StringFragment = 36, + Interpolation = 37, + EscapeSeq = 38, + Boolean = 39, + Regex = 40, + Dict = 41, + NamedArg = 42, + NamedArgPrefix = 43, + FunctionDef = 44, + Params = 45, + NamedParam = 46, + Null = 47, + colon = 48, + CatchExpr = 49, + Block = 51, + FinallyExpr = 52, + Underscore = 55, + Array = 56, + ElseIfExpr = 57, + ElseExpr = 59, + FunctionCallOrIdentifier = 60, + BinOp = 61, + PositionalArg = 62, + WhileExpr = 64, + FunctionCallWithBlock = 66, + TryExpr = 67, + Throw = 69, + CompoundAssign = 71, + Assign = 72 diff --git a/src/parser/shrimp.ts b/src/parser/shrimp.ts index 4f09662..afd774f 100644 --- a/src/parser/shrimp.ts +++ b/src/parser/shrimp.ts @@ -4,24 +4,24 @@ import {operatorTokenizer} from "./operatorTokenizer" import {tokenizer, specializeKeyword} from "./tokenizer" import {trackScope} from "./scopeTracker" import {highlighting} from "./highlight" -const spec_Identifier = {__proto__:null,if:64, null:92, catch:98, finally:104, end:106, else:114, while:128, try:134, throw:138} +const spec_Identifier = {__proto__:null,if:66, null:94, catch:100, finally:106, end:108, else:116, while:130, try:136, throw:140} export const parser = LRParser.deserialize({ version: 14, - states: "9[QYQbOOO!dOSO'#DOOOQa'#DU'#DUO#mQbO'#DeO%RQcO'#E^OOQa'#E^'#E^O&XQcO'#E^O'ZQcO'#E]O'qQcO'#E]O)^QRO'#C}O*mQcO'#EWO*wQcO'#EWO+XQbO'#CzO,SOpO'#CxOOQ`'#EX'#EXO,XQbO'#EWO,cQRO'#DtOOQ`'#EW'#EWO,wQQO'#EVOOQ`'#EV'#EVOOQ`'#Dv'#DvQYQbOOO-PQbO'#DXO-[QbO'#C{O.PQbO'#DmO.tQQO'#DpO.PQbO'#DrO.yQbO'#DQO/RQWO'#DROOOO'#E`'#E`OOOO'#Dw'#DwO/gOSO,59jOOQa,59j,59jOOQ`'#Dx'#DxO/uQbO,5:PO/|QbO'#DVO0WQQO,59pOOQa,5:P,5:PO0cQbO,5:POOQa'#E]'#E]OOQ`'#Dk'#DkOOQ`'#El'#ElOOQ`'#EP'#EPO0mQbO,59cO1gQbO,5:aO.PQbO,59iO.PQbO,59iO.PQbO,59iO.PQbO,5:UO.PQbO,5:UO.PQbO,5:UO1wQRO,59fO2OQRO,59fO2ZQRO,59fO2UQQO,59fO2lQQO,59fO2tObO,59dO3PQbO'#EQO3[QbO,59bO3vQbO,5:ZO1gQbO,5:`OOQ`,5:q,5:qOOQ`-E7t-E7tOOQ`'#Dy'#DyO4ZQbO'#DYO4fQbO'#DZOOQO'#Dz'#DzO4^QQO'#DYO4tQQO,59sO4yQcO'#E]O6_QRO'#E[O6fQRO'#E[OOQO'#E['#E[O6qQQO,59gO6vQRO,5:XO6}QRO,5:XO3vQbO,5:[O7YQcO,5:^O8UQcO,5:^O8`QcO,5:^OOOO,59l,59lOOOO,59m,59mOOOO-E7u-E7uOOQa1G/U1G/UOOQ`-E7v-E7vO8pQQO1G/[OOQa1G/k1G/kO8{QbO1G/kOOQ`,59q,59qOOQO'#D|'#D|O8pQQO1G/[OOQa1G/[1G/[OOQ`'#D}'#D}O8{QbO1G/kOOQ`-E7}-E7}OOQ`1G/{1G/{OOQa1G/T1G/TO:WQcO1G/TO:_QcO1G/TO:fQcO1G/TOOQa1G/p1G/pO;_QcO1G/pO;iQcO1G/pO;sQcO1G/pOOQa1G/Q1G/QOOQa1G/O1G/OO]QbO1G/uOOQ`1G/z1G/zOOQ`-E7w-E7wO>hQQO,59tOOQO,59u,59uOOQO-E7x-E7xO>pQbO1G/_O3vQbO1G/RO3vQbO1G/sO?TQbO1G/vO?`QQO7+$vOOQa7+$v7+$vO?kQbO7+%VOOQa7+%V7+%VOOQO-E7z-E7zOOQ`-E7{-E7{OOQ`'#D{'#D{O?uQQO'#D{O?zQbO'#EiOOQ`,59z,59zO@kQbO'#D^O@pQQO'#DaOOQ`7+%a7+%aO@uQbO7+%aO@zQbO7+%aOASQbO7+$yOA_QbO7+$yOA{QbO7+$mOBTQbO7+%_OOQ`7+%b7+%bOBYQbO7+%bOB_QbO7+%bOOQa<gAN>gOOQ`AN>PAN>POCuQbOAN>POCzQbOAN>POOQ`-E7|-E7|OOQ`AN=sAN=sODSQbOAN=sO-[QbO,5:QO3vQbO,5:SOOQ`AN>hAN>hOOQ`7+%O7+%OOOQ`G23kG23kODXQbOG23kPD^QbO'#DfOOQ`G23_G23_ODcQQO1G/lOOQ`1G/n1G/nOOQ`LD)VLD)VO3vQbO7+%WOOQ`<]QbO1G/vOOQ`1G/{1G/{OOQ`-E7x-E7xO>hQQO,59uOOQO,59v,59vOOQO-E7y-E7yO>pQbO1G/`O3vQbO1G/SO3vQbO1G/tO?TQbO1G/wO?`QQO7+$wOOQa7+$w7+$wO?kQbO7+%WOOQa7+%W7+%WOOQO-E7{-E7{OOQ`-E7|-E7|OOQ`'#D|'#D|O?uQQO'#D|O?zQbO'#EiOOQ`,59{,59{O@kQbO'#D_O@pQQO'#DbOOQ`7+%b7+%bO@uQbO7+%bO@zQbO7+%bOASQbO7+$zOA_QbO7+$zOA{QbO7+$nOBTQbO7+%`OOQ`7+%c7+%cOBYQbO7+%cOB_QbO7+%cOOQa<hAN>hOOQ`AN>QAN>QOCuQbOAN>QOCzQbOAN>QOOQ`-E7}-E7}OOQ`AN=tAN=tODSQbOAN=tO-[QbO,5:RO3vQbO,5:TOOQ`AN>iAN>iOOQ`7+%P7+%POOQ`G23lG23lODXQbOG23lPD^QbO'#DgOOQ`G23`G23`ODcQQO1G/mOOQ`1G/o1G/oOOQ`LD)WLD)WO3vQbO7+%XOOQ`<q#c#f,Y#f#g?n#g#h,Y#h#i@k#i#o,Y#o#p#{#p#qBo#q;'S#{;'S;=`$d<%l~#{~O#{~~CYS$QUsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{S$gP;=`<%l#{^$qUsS!wYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UsS#[QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%uZsS!xYOY%nYZ#{Zt%ntu&huw%nwx&hx#O%n#O#P&h#P;'S%n;'S;=`'P<%lO%nY&mS!xYOY&hZ;'S&h;'S;=`&y<%lO&hY&|P;=`<%l&h^'SP;=`<%l%n~'[O#T~~'aO#R~U'hUsS!}QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(RUsS#_QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(jWsSOt#{uw#{x!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U)ZYsSmQOt#{uw#{x!O#{!O!P)y!P!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U*OWsSOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U*oWsSmQOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U+^^sSOt#{uw#{x}#{}!O,Y!O!Q#{!Q![)S![!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{U,_[sSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{U-[UzQsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U-sWsSOt#{uw#{x!P#{!P!Q.]!Q#O#{#P;'S#{;'S;=`$d<%lO#{U.b^sSOY/^YZ#{Zt/^tu0auw/^wx0ax!P/^!P!Q#{!Q!}/^!}#O5S#O#P2o#P;'S/^;'S;=`6T<%lO/^U/e^sSwQOY/^YZ#{Zt/^tu0auw/^wx0ax!P/^!P!Q3U!Q!}/^!}#O5S#O#P2o#P;'S/^;'S;=`6T<%lO/^Q0fXwQOY0aZ!P0a!P!Q1R!Q!}0a!}#O1p#O#P2o#P;'S0a;'S;=`3O<%lO0aQ1UP!P!Q1XQ1^UwQ#Z#[1X#]#^1X#a#b1X#g#h1X#i#j1X#m#n1XQ1sVOY1pZ#O1p#O#P2Y#P#Q0a#Q;'S1p;'S;=`2i<%lO1pQ2]SOY1pZ;'S1p;'S;=`2i<%lO1pQ2lP;=`<%l1pQ2rSOY0aZ;'S0a;'S;=`3O<%lO0aQ3RP;=`<%l0aU3ZWsSOt#{uw#{x!P#{!P!Q3s!Q#O#{#P;'S#{;'S;=`$d<%lO#{U3zbsSwQOt#{uw#{x#O#{#P#Z#{#Z#[3s#[#]#{#]#^3s#^#a#{#a#b3s#b#g#{#g#h3s#h#i#{#i#j3s#j#m#{#m#n3s#n;'S#{;'S;=`$d<%lO#{U5X[sSOY5SYZ#{Zt5Stu1puw5Swx1px#O5S#O#P2Y#P#Q/^#Q;'S5S;'S;=`5}<%lO5SU6QP;=`<%l5SU6WP;=`<%l/^U6bUsS!PQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U6{W#ZQsSOt#{uw#{x!_#{!_!`7e!`#O#{#P;'S#{;'S;=`$d<%lO#{U7jVsSOt#{uw#{x#O#{#P#Q8P#Q;'S#{;'S;=`$d<%lO#{U8WU#YQsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~8oO#U~U8vU#^QsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9aUsS!WQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9x]sSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#U:q#U#o,Y#o;'S#{;'S;=`$d<%lO#{U:v^sSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#`,Y#`#a;r#a#o,Y#o;'S#{;'S;=`$d<%lO#{U;w^sSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#g,Y#g#hx[#VWsSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^?u[#XWsSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^@r^#WWsSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#f,Y#f#gAn#g#o,Y#o;'S#{;'S;=`$d<%lO#{UAs^sSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#i,Y#i#jc#Y#o,w#o;'S#{;'S;=`$d<%lO#{U>j[wQtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^?g[#VWtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^@d[#XWtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^Aa^#WWtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#f,w#f#gB]#g#o,w#o;'S#{;'S;=`$d<%lO#{UBb^tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#i,w#i#j=b#j#o,w#o;'S#{;'S;=`$d<%lO#{UCeU!aQtSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~C|O#a~", tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!|~~", 11)], - topRules: {"Program":[0,25]}, + topRules: {"Program":[0,26]}, specialized: [{term: 20, get: (value: any, stack: any) => (specializeKeyword(value, stack) << 1), external: specializeKeyword},{term: 20, get: (value: keyof typeof spec_Identifier) => spec_Identifier[value] || -1}], tokenPrec: 1634 }) diff --git a/src/parser/tests/basics.test.ts b/src/parser/tests/basics.test.ts index b4092a9..dea9d7b 100644 --- a/src/parser/tests/basics.test.ts +++ b/src/parser/tests/basics.test.ts @@ -48,7 +48,6 @@ describe('Identifier', () => { FunctionCallOrIdentifier Identifier even?`) }) - }) describe('Unicode Symbol Support', () => { @@ -637,26 +636,51 @@ describe('DotGet whitespace sensitivity', () => { }) describe('Comments', () => { - test('are barely there', () => { - expect(`x = 5 # one banana\ny = 2 # two bananas`).toMatchTree(` + test('are greedy', () => { + expect(` +x = 5 # one banana +y = 2 # two bananas`).toMatchTree(` Assign AssignableIdentifier x Eq = Number 5 + Comment # one banana Assign AssignableIdentifier y Eq = - Number 2`) + Number 2 + Comment # two bananas`) - expect('# some comment\nbasename = 5 # very astute\n basename / prop\n# good info').toMatchTree(` - Assign - AssignableIdentifier basename - Eq = - Number 5 - BinOp - Identifier basename - Slash / - Identifier prop`) + expect(` +# some comment +basename = 5 # very astute + basename / prop +# good info`).toMatchTree(` + Comment # some comment + Assign + AssignableIdentifier basename + Eq = + Number 5 + Comment # very astute + BinOp + Identifier basename + Slash / + Identifier prop + Comment # good info`) + }) + + test('words with # are not considered comments', () => { + expect('find #hashtag-file.txt').toMatchTree(` + FunctionCall + Identifier find + PositionalArg + Word #hashtag-file.txt`) + }) + + test('hastags in strings are not comments', () => { + expect("'this is not a #comment'").toMatchTree(` + String + StringFragment this is not a #comment`) }) }) @@ -697,7 +721,6 @@ describe('Array destructuring', () => { Number 2`) }) - test('works with dotget', () => { expect('[ a ] = [ [1 2 3] ]; a.1').toMatchTree(` Assign @@ -800,4 +823,4 @@ Assign keyword end `) }) -}) \ No newline at end of file +}) diff --git a/src/parser/tests/literals.test.ts b/src/parser/tests/literals.test.ts index 693da17..3a63381 100644 --- a/src/parser/tests/literals.test.ts +++ b/src/parser/tests/literals.test.ts @@ -150,8 +150,11 @@ describe('array literals', () => { 2 # second ]`).toMatchTree(` Array + Comment # something... Number 1 + Comment # first Number 2 + Comment # second `) }) @@ -397,12 +400,15 @@ c=3]`).toMatchTree(` c=3 ]`).toMatchTree(` Dict + Comment # something... NamedArg NamedArgPrefix a= Number 1 + Comment # first NamedArg NamedArgPrefix b= Number 2 + Comment # second NamedArg NamedArgPrefix c= Number 3 diff --git a/vscode-extension/shrimp-0.0.1.vsix b/vscode-extension/shrimp-0.0.1.vsix new file mode 100644 index 0000000..730cc92 Binary files /dev/null and b/vscode-extension/shrimp-0.0.1.vsix differ