Skip to content

Commit

Permalink
support undefined as a first-class value (#164)
Browse files Browse the repository at this point in the history
  • Loading branch information
imaman authored Apr 25, 2024
1 parent 1809c1d commit aa696b4
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 21 deletions.
6 changes: 6 additions & 0 deletions modules/septima-lang/change-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@
### PR/163

- retire `sink` - it was too confusing + there are some things that undefined (in JS) can do but sink could not

### PR/164

- undefined is now a first class value: `let x = undefined`
- `{a: undefined, n: 42}` is identical to `{n: 42}`
- `undefined ?? 42` is `42`
5 changes: 3 additions & 2 deletions modules/septima-lang/src/ast-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export type Import = {

export type Literal = {
tag: 'literal'
type: 'str' | 'bool' | 'num'
type: 'str' | 'bool' | 'num' | 'undef'
t: Token
unitId: UnitId
}
Expand Down Expand Up @@ -70,7 +70,7 @@ export type AstNode =
}
| {
tag: 'binaryOperator'
operator: '+' | '-' | '*' | '/' | '**' | '%' | '&&' | '||' | '>' | '<' | '>=' | '<=' | '==' | '!='
operator: '+' | '-' | '*' | '/' | '**' | '%' | '&&' | '||' | '>' | '<' | '>=' | '<=' | '==' | '!=' | '??'
lhs: AstNode
rhs: AstNode
unitId: UnitId
Expand Down Expand Up @@ -181,6 +181,7 @@ export function show(ast: AstNode | AstNode[]): string {
return switchOn(ast.type, {
bool: () => ast.t.text,
num: () => ast.t.text,
undef: () => 'undefined',
str: () => `'${ast.t.text}'`,
})
}
Expand Down
17 changes: 15 additions & 2 deletions modules/septima-lang/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export class Parser {
switchOn(pathToImportFrom.type, {
bool: notString,
num: notString,
undef: notString,
str: () => {},
})
ret.push({ start, ident, pathToImportFrom: pathToImportFrom.t, unitId: this.unitId })
Expand Down Expand Up @@ -210,7 +211,7 @@ export class Parser {
}

ternary(): AstNode {
const condition = this.or()
const condition = this.undefinedCoallesing()
if (this.scanner.headMatches('??')) {
return condition
}
Expand All @@ -226,6 +227,14 @@ export class Parser {
return { tag: 'ternary', condition, positive, negative, unitId: this.unitId }
}

undefinedCoallesing(): AstNode {
const lhs = this.or()
if (this.scanner.consumeIf('??')) {
return { tag: 'binaryOperator', operator: '??', lhs, rhs: this.undefinedCoallesing(), unitId: this.unitId }
}
return lhs
}

or(): AstNode {
const lhs = this.and()
if (this.scanner.consumeIf('||')) {
Expand Down Expand Up @@ -402,7 +411,11 @@ export class Parser {
}

maybePrimitiveLiteral(): Literal | undefined {
let t = this.scanner.consumeIf('true')
let t = this.scanner.consumeIf('undefined')
if (t) {
return { tag: 'literal', type: 'undef', t, unitId: this.unitId }
}
t = this.scanner.consumeIf('true')
if (t) {
return { tag: 'literal', type: 'bool', t, unitId: this.unitId }
}
Expand Down
10 changes: 9 additions & 1 deletion modules/septima-lang/src/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,10 @@ export class Runtime {
return lhs.over(rhs)
}

if (ast.operator === '??') {
return lhs.coalesce(() => this.evalNode(ast.rhs, table))
}

shouldNeverHappen(ast.operator)
}

Expand Down Expand Up @@ -284,6 +288,10 @@ export class Runtime {
if (ast.type === 'str') {
return Value.str(ast.t.text)
}

if (ast.type === 'undef') {
return Value.undef()
}
shouldNeverHappen(ast.type)
}

Expand Down Expand Up @@ -323,7 +331,7 @@ export class Runtime {
})

// TODO(imaman): verify type of all keys (strings, maybe also numbers)
return Value.obj(Object.fromEntries(entries))
return Value.obj(Object.fromEntries(entries.filter(([_, v]) => !v.isUndefined())))
}

if (ast.tag === 'lambda') {
Expand Down
Loading

0 comments on commit aa696b4

Please sign in to comment.