Skip to content

Commit

Permalink
feat: function literals (#23)
Browse files Browse the repository at this point in the history
* fix: update goroutine state on unknown instruction

Also fixed a bug where an failed result is being unwrapped

* feat: add `FunctionLiteral` grammar and ECE type

* feat: implement `FunctionLiteral` in ECE

* refactor: minor edits to error message
  • Loading branch information
shenyih0ng authored Apr 7, 2024
1 parent 6c72359 commit 8fd8dd9
Show file tree
Hide file tree
Showing 6 changed files with 358 additions and 250 deletions.
4 changes: 2 additions & 2 deletions src/go-slang/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class FuncArityError extends RuntimeSourceError {
}
}

export class GoExprMustBeFunctionError extends RuntimeSourceError {
export class GoExprMustBeFunctionCallError extends RuntimeSourceError {
private expr: string

public location: NodeLocation
Expand All @@ -85,7 +85,7 @@ export class GoExprMustBeFunctionError extends RuntimeSourceError {
}

public explain() {
return `expression in go statement must be function call, not ${this.expr}`
return `expression in go must be function call, not ${this.expr}`
}
}

Expand Down
15 changes: 13 additions & 2 deletions src/go-slang/goroutine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Stack } from '../cse-machine/utils'
import { RuntimeSourceError } from '../errors/runtimeSourceError'
import {
FuncArityError,
GoExprMustBeFunctionError,
GoExprMustBeFunctionCallError,
UndefinedError,
UnknownInstructionError
} from './error'
Expand Down Expand Up @@ -36,6 +36,7 @@ import {
ForStartMarker,
ForStatement,
FunctionDeclaration,
FunctionLiteral,
GoRoutineOp,
GoStatement,
Identifier,
Expand Down Expand Up @@ -104,6 +105,7 @@ export class GoRoutine {
const inst = H.resolve(C.pop()) as Instruction

if (!Interpreter.hasOwnProperty(inst.type)) {
this.state = GoRoutineState.Exited
return Result.fail(new UnknownInstructionError(inst.type))
}

Expand Down Expand Up @@ -197,7 +199,7 @@ const Interpreter: {

GoStatement: ({ call, loc }: GoStatement, { C, H, A }) => {
if (call.type !== NodeType.CallExpression) {
return Result.fail(new GoExprMustBeFunctionError(call.type, loc!))
return Result.fail(new GoExprMustBeFunctionCallError(call.type, loc!))
}

const { callee, args } = call as CallExpression
Expand All @@ -221,6 +223,15 @@ const Interpreter: {

Literal: (inst: Literal, { S, H }) => S.push(H.alloc(inst.value)),

FunctionLiteral: (funcLitNode: FunctionLiteral, { S, E, H }) =>
S.push(
H.alloc({
type: CommandType.ClosureOp,
funcDeclNodeUid: funcLitNode.uid,
envId: E.id()
} as ClosureOp)
),

TypeLiteral: (inst: TypeLiteral, { S }) => S.push(inst),

Identifier: ({ name, loc }: Identifier, { S, E, H }) => {
Expand Down
560 changes: 317 additions & 243 deletions src/go-slang/parser/go.js

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions src/go-slang/parser/go.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ IdentifierPart

Literal
= BasicLit
/ FunctionLit

BasicLit
= IntegerLit
Expand Down Expand Up @@ -263,6 +264,12 @@ ShortVariableDeclaration
return makeNode({ type: "VariableDeclaration", left, right })
}

/* Function Literal */
FunctionLit "function literal"
= FUNC_TOKEN _ params:Signature _ body:Block EOS {
return makeNode({ type: "FunctionLiteral", params, body })
}

/* Function Declaration */

FunctionDeclaration "function declaration"
Expand Down
5 changes: 4 additions & 1 deletion src/go-slang/scheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ export class Scheduler {
let remainingTime = timeQuanta
while (remainingTime--) {
const result = routine.tick()
if (result.isFailure) { this.slangContext.errors.push(result.error as RuntimeSourceError) } // prettier-ignore
if (result.isFailure) {
this.slangContext.errors.push(result.error as RuntimeSourceError)
break
}
// if the routine is no longer running we schedule it out
if (result.unwrap() !== GoRoutineState.Running) { break } // prettier-ignore
}
Expand Down
17 changes: 15 additions & 2 deletions src/go-slang/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export enum NodeType {
BinaryExpression = 'BinaryExpression',
Identifier = 'Identifier',
Literal = 'Literal',
FunctionLiteral = 'FunctionLiteral',
TypeLiteral = 'TypeLiteral',
CallExpression = 'CallExpression'
}
Expand All @@ -40,7 +41,13 @@ type Statement =

type SimpleStatement = ExpressionStatement | Assignment | Declaration

type Expression = Identifier | Literal | UnaryExpression | BinaryExpression | CallExpression
type Expression =
| Identifier
| Literal
| FunctionLiteral
| UnaryExpression
| BinaryExpression
| CallExpression

interface Position {
line: number
Expand Down Expand Up @@ -172,6 +179,12 @@ export interface Literal extends Node {

export const True: Literal = { type: NodeType.Literal, value: true }

export interface FunctionLiteral extends Node {
type: NodeType.FunctionLiteral
params: Identifier[]
body: Block
}

export enum Type {
Channel = 'chan'
}
Expand Down Expand Up @@ -222,7 +235,7 @@ export interface BinaryExpression extends Node {

export interface CallExpression extends Node {
type: NodeType.CallExpression
callee: Identifier
callee: Identifier | FunctionLiteral
args: Expression[]
}

Expand Down

0 comments on commit 8fd8dd9

Please sign in to comment.