From 447e70041de76d1ebc0e946836805e2986d6c0be Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Tue, 7 Oct 2025 08:12:50 -0700 Subject: [PATCH] wip --- src/parser/contextTracker.ts | 26 ++++++++++++ src/parser/old-shrimp.grammar | 79 ----------------------------------- src/parser/shrimp.grammar | 11 ++++- src/parser/shrimp.terms.ts | 2 +- src/parser/shrimp.test.ts | 36 ++++++++++++---- src/parser/shrimp.ts | 16 +++---- 6 files changed, 71 insertions(+), 99 deletions(-) create mode 100644 src/parser/contextTracker.ts delete mode 100644 src/parser/old-shrimp.grammar diff --git a/src/parser/contextTracker.ts b/src/parser/contextTracker.ts new file mode 100644 index 0000000..35e63e8 --- /dev/null +++ b/src/parser/contextTracker.ts @@ -0,0 +1,26 @@ +import { ContextTracker } from '@lezer/lr' +import { Assignment } from '#parser/shrimp.terms' + +interface ParserContext { + definedVariables: Set +} + +export const contextTracker = new ContextTracker({ + start: { definedVariables: new Set() }, + + reduce(context, term, stack, input) { + console.log(`🤏 REDUCE`, termToString(term)) + if (term !== Assignment) return context + + return context + }, + + shift(context, term, stack, input) { + console.log(` ⇧ SHIFT `, termToString(term)) + return context + }, +}) + +const termToString = (term: number) => { + return Object.entries(require('./shrimp.terms')).find(([k, v]) => v === term)?.[0] || term +} diff --git a/src/parser/old-shrimp.grammar b/src/parser/old-shrimp.grammar deleted file mode 100644 index c33a3c6..0000000 --- a/src/parser/old-shrimp.grammar +++ /dev/null @@ -1,79 +0,0 @@ -@external propSource highlighting from "./highlight.js" -@top Program { line* } - -line { - CommandCall semi | - expr semi -} - -@skip { space } - -@tokens { - @precedence { Number "-"} - space { @whitespace+ } - Number { "-"? $[0-9]+ ('.' $[0-9]+)? } - Boolean { "true" | "false" } - String { '\'' !["]* '\'' } - NamedArgPrefix { $[a-z]+ $[a-z0-9\-]* "=" } // matches "lines=", "follow=", etc. - - fn[@name=keyword] { "fn" } - equals[@name=operator] { "=" } - ":"[@name=colon] - "+"[@name=operator] - "-"[@name=operator] - "*"[@name=operator] - "/"[@name=operator] - leftParen[@name=paren] { "(" } - rightParen[@name=paren] { ")" } -} - -@external tokens tokenizer from "./tokenizers" { - Identifier, - Command, - CommandPartial -} - -@external tokens argTokenizer from "./tokenizers" { - UnquotedArg -} - -@external tokens insertSemicolon from "./tokenizers" { insertedSemi } - -@precedence { - multiplicative @left, - additive @left, - namedComplete @left, - function @right - assignment @right -} - -expr { - Assignment | - Function | - BinOp | - atom -} - -semi { insertedSemi | ";" } - -argValue { atom | UnquotedArg } - -CommandCall { (Command | CommandPartial) (NamedArg | PartialNamedArg | Arg)* } -Arg { !namedComplete argValue } -NamedArg { NamedArgPrefix !namedComplete argValue } // Required atom, higher precedence -PartialNamedArg { NamedArgPrefix } // Just the prefix - -Assignment { Identifier !assignment equals expr } - -Function { !function fn Params ":" expr } -Params { Identifier* } - -BinOp { - expr !multiplicative "*" expr | - expr !multiplicative "/" expr | - expr !additive "+" expr | - expr !additive "-" expr -} - -ParenExpr { leftParen expr rightParen } -atom { Identifier ~command | Number | String | Boolean | ParenExpr } diff --git a/src/parser/shrimp.grammar b/src/parser/shrimp.grammar index 7661996..f4c897d 100644 --- a/src/parser/shrimp.grammar +++ b/src/parser/shrimp.grammar @@ -17,7 +17,6 @@ rightParen { ")" } ":" "fn" - "do" "end" "=" "+"[@name=operator] @@ -73,7 +72,15 @@ NamedArg { } FunctionDef { - "fn" Params ":" "do" expression "end" + singleLineFunctionDef | multiLineFunctionDef +} + +singleLineFunctionDef { + "fn" Params ":" expression "end" +} + +multiLineFunctionDef { + "fn" Params ":" newline (expression newline)* "end" } Params { diff --git a/src/parser/shrimp.terms.ts b/src/parser/shrimp.terms.ts index 109eda1..c76ef37 100644 --- a/src/parser/shrimp.terms.ts +++ b/src/parser/shrimp.terms.ts @@ -15,4 +15,4 @@ export const NamedArgPrefix = 17, FunctionDef = 18, Params = 20, - Assignment = 24 + Assignment = 23 diff --git a/src/parser/shrimp.test.ts b/src/parser/shrimp.test.ts index 5285587..5348eba 100644 --- a/src/parser/shrimp.test.ts +++ b/src/parser/shrimp.test.ts @@ -192,24 +192,22 @@ describe('BinOp', () => { describe('Fn', () => { test('parses function no parameters', () => { - expect('fn: do 1 end').toMatchTree(` + expect('fn: 1 end').toMatchTree(` FunctionDef fn fn Params : : - do do Number 1 end end`) }) test('parses function with single parameter', () => { - expect('fn x: do x + 1 end').toMatchTree(` + expect('fn x: x + 1 end').toMatchTree(` FunctionDef fn fn Params Identifier x : : - do do BinOp Identifier x operator + @@ -218,23 +216,44 @@ describe('Fn', () => { }) test('parses function with multiple parameters', () => { - expect('fn x y: do x * y end').toMatchTree(` + expect('fn x y: x * y end').toMatchTree(` FunctionDef fn fn Params Identifier x Identifier y : : - do do BinOp Identifier x operator * Identifier y end end`) }) + + test('parses multiline function with multiple statements', () => { + expect(`fn x y: + x * y + x + 9 +end`).toMatchTree(` + FunctionDef + fn fn + Params + Identifier x + Identifier y + : : + BinOp + Identifier x + operator * + Identifier y + BinOp + Identifier x + operator + + Number 9 + end end`) + }) }) -describe('abmiguity', () => { +describe('ambiguity', () => { test('parses ambiguous expressions correctly', () => { expect('a + -3').toMatchTree(` BinOp @@ -267,7 +286,7 @@ describe('Assignment', () => { }) test('parses assignment with functions', () => { - expect('add = fn a b: do a + b end').toMatchTree(` + expect('add = fn a b: a + b end').toMatchTree(` Assignment Identifier add = = @@ -277,7 +296,6 @@ describe('Assignment', () => { Identifier a Identifier b : : - do do BinOp Identifier a operator + diff --git a/src/parser/shrimp.ts b/src/parser/shrimp.ts index 36f6a81..ef659f6 100644 --- a/src/parser/shrimp.ts +++ b/src/parser/shrimp.ts @@ -4,16 +4,16 @@ import {tokenizer} from "./tokenizers" import {highlighting} from "./highlight.js" export const parser = LRParser.deserialize({ version: 14, - states: "&YQVQTOOOnQPO'#DSO!tQUO'#DSO#OQPOOOOQO'#DR'#DRO#oQTO'#CbOOQS'#DP'#DPO#vQTO'#CnOOQO'#C|'#C|O$OQPO'#CvQVQTOOOOQS'#DO'#DOOOQS'#Ca'#CaO$TQTO'#ClOOQS'#C}'#C}OOQS'#Cw'#CwO$[QUO,58zOVQTO,59`O$lQTO,58}O$lQTO,58}O$sQPO,58|O%UQUO'#DSO%]QPO,58|OOQS'#Cx'#CxO%bQTO'#CpO%jQPO,59YOOQS,59b,59bOOQS-E6t-E6tOOQS,59W,59WOOQS-E6u-E6uOOQO1G.z1G.zOOQO'#DS'#DSOOQO1G.i1G.iO%oQPO1G.iOOQS1G.h1G.hOOQS-E6v-E6vO&WQPO1G.tO$lQTO7+$`O&]QPO<