Skip to content

Commit 30e841f

Browse files
committed
Added builtin functions for source 1, 2.
1 parent a058ddb commit 30e841f

File tree

3 files changed

+283
-129
lines changed

3 files changed

+283
-129
lines changed

src/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { simple } from 'acorn-walk/dist/walk'
2-
import { generate } from 'astring'
32
import { DebuggerStatement, Literal, Program } from 'estree'
43
import { RawSourceMap, SourceMapConsumer } from 'source-map'
54
import { JSSLANG_PROPERTIES, UNKNOWN_LOCATION } from './constants'
@@ -15,7 +14,7 @@ import {
1514
import { parse, parseAt } from './parser'
1615
import { AsyncScheduler, PreemptiveScheduler } from './schedulers'
1716
import { areBreakpointsSet, setBreakpointAtLine } from './stdlib/inspector'
18-
import { getEvaluationSteps, treeifyMain } from './substituter'
17+
import { codify, getEvaluationSteps } from './substituter'
1918
import { transpile } from './transpiler'
2019
import {
2120
Context,
@@ -171,7 +170,7 @@ export async function runInContext(
171170
const steps = getEvaluationSteps(program, context)
172171
return Promise.resolve({
173172
status: 'finished',
174-
value: steps.map(treeifyMain).map(generate)
173+
value: steps.map(codify)
175174
} as Result)
176175
}
177176
const isNativeRunnable = determineExecutionMethod(theOptions, context, program)

src/substituter.ts

Lines changed: 130 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
// import { generate } from 'astring'
1+
import { generate } from 'astring'
22
import * as es from 'estree'
3-
// import createContext from './createContext'
3+
import createContext from './createContext'
44
import * as errors from './interpreter-errors'
55
import { parse } from './parser'
6-
import { listPrelude } from './stdlib/list.prelude'
76
import { BlockExpression, Context, FunctionDeclarationExpression, substituterNodes } from './types'
87
import * as ast from './utils/astCreator'
98
import {
@@ -16,6 +15,7 @@ import {
1615
} from './utils/dummyAstCreator'
1716
import { evaluateBinaryExpression, evaluateUnaryExpression } from './utils/operators'
1817
import * as rttc from './utils/rttc'
18+
import * as builtin from './utils/substituter'
1919

2020
const irreducibleTypes = new Set<string>([
2121
'Identifier',
@@ -52,17 +52,7 @@ function substituteMain(
5252
): es.Identifier | FunctionDeclarationExpression | es.Literal | es.Expression {
5353
if (replacement.type === 'Literal') {
5454
// only accept string, boolean and numbers for arguments
55-
if (!['string', 'boolean', 'number'].includes(typeof replacement.value)) {
56-
throw new rttc.TypeError(
57-
replacement,
58-
'',
59-
'string, boolean or number',
60-
typeof replacement.value
61-
)
62-
} else {
63-
// target as Identifier is guaranteed to be a tree.
64-
return target.name === name.name ? ast.primitive(replacement.value) : target
65-
}
55+
return target.name === name.name ? ast.primitive(replacement.value) : target
6656
} else {
6757
return target.name === name.name
6858
? (substitute(replacement) as FunctionDeclarationExpression)
@@ -248,6 +238,13 @@ function substituteMain(
248238
? (substitute(target.alternate) as es.BlockStatement)
249239
: null
250240
return substedIfStatement
241+
},
242+
243+
ArrayExpression(target: es.ArrayExpression): es.ArrayExpression {
244+
const substedArray = ast.arrayExpression([dummyExpression()])
245+
seenBefore.set(target, substedArray)
246+
substedArray.elements = target.elements.map(substitute) as es.Expression[]
247+
return substedArray
251248
}
252249
}
253250

@@ -324,12 +321,7 @@ const reducers = {
324321

325322
ExpressionStatement(node: es.ExpressionStatement, context: Context): [substituterNodes, Context] {
326323
const [reduced] = reduce(node.expression, context)
327-
return [
328-
reduced.type.includes('Statement')
329-
? reduced
330-
: ast.expressionStatement(reduced as es.Expression),
331-
context
332-
]
324+
return [ast.expressionStatement(reduced as es.Expression), context]
333325
},
334326

335327
BinaryExpression(node: es.BinaryExpression, context: Context): [substituterNodes, Context] {
@@ -499,15 +491,17 @@ const reducers = {
499491
}
500492
}
501493
// if it reaches here, means all the arguments are legal.
502-
return [
503-
callee.type === 'FunctionExpression' || callee.type === 'ArrowFunctionExpression'
504-
? apply(
505-
callee as FunctionDeclarationExpression,
506-
args as Array<es.Literal | es.Identifier>
507-
)
508-
: context.runtime.environments[0].head[(callee as es.Identifier).name](...args),
509-
context
510-
]
494+
if (['FunctionExpression', 'ArrowFunctionExpression'].includes(callee.type)) {
495+
return [
496+
apply(callee as FunctionDeclarationExpression, args as Array<es.Literal | es.Identifier>),
497+
context
498+
]
499+
} else {
500+
if ((callee as es.Identifier).name.includes('math')) {
501+
return [builtin.evaluateMath((callee as es.Identifier).name, ...args), context]
502+
}
503+
return [builtin[(callee as es.Identifier).name](...args), context]
504+
}
511505
}
512506
},
513507

@@ -822,106 +816,109 @@ function reduce(node: substituterNodes, context: Context): [substituterNodes, Co
822816
}
823817
}
824818

825-
export function treeifyMain(program: es.Program): es.Program {
826-
// recurse down the program like substitute
827-
// if see a function at expression position,
828-
// has an identifier: replace with the name
829-
// else: replace with an identifer "=>"
830-
const treeifiers = {
831-
// Identifier: return
832-
ExpressionStatement: (target: es.ExpressionStatement): es.ExpressionStatement => {
833-
return ast.expressionStatement(treeify(target.expression) as es.Expression)
834-
},
819+
// recurse down the program like substitute
820+
// if see a function at expression position,
821+
// has an identifier: replace with the name
822+
// else: replace with an identifer "=>"
823+
const treeifiers = {
824+
// Identifier: return
825+
ExpressionStatement: (target: es.ExpressionStatement): es.ExpressionStatement => {
826+
return ast.expressionStatement(treeify(target.expression) as es.Expression)
827+
},
835828

836-
BinaryExpression: (target: es.BinaryExpression) => {
837-
return ast.binaryExpression(
838-
target.operator,
839-
treeify(target.left) as es.Expression,
840-
treeify(target.right) as es.Expression
841-
)
842-
},
829+
BinaryExpression: (target: es.BinaryExpression) => {
830+
return ast.binaryExpression(
831+
target.operator,
832+
treeify(target.left) as es.Expression,
833+
treeify(target.right) as es.Expression
834+
)
835+
},
843836

844-
UnaryExpression: (target: es.UnaryExpression): es.UnaryExpression => {
845-
return ast.unaryExpression(target.operator, treeify(target.argument) as es.Expression)
846-
},
837+
UnaryExpression: (target: es.UnaryExpression): es.UnaryExpression => {
838+
return ast.unaryExpression(target.operator, treeify(target.argument) as es.Expression)
839+
},
847840

848-
ConditionalExpression: (target: es.ConditionalExpression): es.ConditionalExpression => {
849-
return ast.conditionalExpression(
850-
treeify(target.test) as es.Expression,
851-
treeify(target.consequent) as es.Expression,
852-
treeify(target.alternate) as es.Expression
853-
)
854-
},
841+
ConditionalExpression: (target: es.ConditionalExpression): es.ConditionalExpression => {
842+
return ast.conditionalExpression(
843+
treeify(target.test) as es.Expression,
844+
treeify(target.consequent) as es.Expression,
845+
treeify(target.alternate) as es.Expression
846+
)
847+
},
855848

856-
CallExpression: (target: es.CallExpression): es.CallExpression => {
857-
return ast.callExpression(
858-
treeify(target.callee) as es.Expression,
859-
target.arguments.map(arg => treeify(arg) as es.Expression)
860-
)
861-
},
849+
CallExpression: (target: es.CallExpression): es.CallExpression => {
850+
return ast.callExpression(
851+
treeify(target.callee) as es.Expression,
852+
target.arguments.map(arg => treeify(arg) as es.Expression)
853+
)
854+
},
862855

863-
FunctionDeclaration: (target: es.FunctionDeclaration): es.FunctionDeclaration => {
864-
return ast.functionDeclaration(target.id, target.params, treeify(
865-
target.body
866-
) as es.BlockStatement)
867-
},
856+
FunctionDeclaration: (target: es.FunctionDeclaration): es.FunctionDeclaration => {
857+
return ast.functionDeclaration(target.id, target.params, treeify(
858+
target.body
859+
) as es.BlockStatement)
860+
},
868861

869-
// CORE
870-
FunctionExpression: (target: es.FunctionExpression): es.Identifier => {
871-
return ast.identifier(target.id ? target.id.name : '=>')
872-
},
862+
// CORE
863+
FunctionExpression: (target: es.FunctionExpression): es.Identifier => {
864+
return ast.identifier(target.id ? target.id.name : '=>')
865+
},
873866

874-
Program: (target: es.Program): es.Program => {
875-
return ast.program(target.body.map(stmt => treeify(stmt) as es.Statement))
876-
},
867+
Program: (target: es.Program): es.Program => {
868+
return ast.program(target.body.map(stmt => treeify(stmt) as es.Statement))
869+
},
877870

878-
BlockStatement: (target: es.BlockStatement): es.BlockStatement => {
879-
return ast.blockStatement(target.body.map(stmt => treeify(stmt) as es.Statement))
880-
},
871+
BlockStatement: (target: es.BlockStatement): es.BlockStatement => {
872+
return ast.blockStatement(target.body.map(stmt => treeify(stmt) as es.Statement))
873+
},
881874

882-
ReturnStatement: (target: es.ReturnStatement): es.ReturnStatement => {
883-
return ast.returnStatement(treeify(target.argument!) as es.Expression)
884-
},
875+
ReturnStatement: (target: es.ReturnStatement): es.ReturnStatement => {
876+
return ast.returnStatement(treeify(target.argument!) as es.Expression)
877+
},
885878

886-
BlockExpression: (target: BlockExpression): es.BlockStatement => {
887-
return ast.blockStatement(target.body.map(treeify) as es.Statement[])
888-
},
879+
BlockExpression: (target: BlockExpression): es.BlockStatement => {
880+
return ast.blockStatement(target.body.map(treeify) as es.Statement[])
881+
},
889882

890-
// source 1
891-
VariableDeclaration: (target: es.VariableDeclaration): es.VariableDeclaration => {
892-
return ast.variableDeclaration(target.declarations.map(treeify) as es.VariableDeclarator[])
893-
},
883+
// source 1
884+
VariableDeclaration: (target: es.VariableDeclaration): es.VariableDeclaration => {
885+
return ast.variableDeclaration(target.declarations.map(treeify) as es.VariableDeclarator[])
886+
},
894887

895-
VariableDeclarator: (target: es.VariableDeclarator): es.VariableDeclarator => {
896-
return ast.variableDeclarator(target.id, treeify(target.init!) as es.Expression)
897-
},
888+
VariableDeclarator: (target: es.VariableDeclarator): es.VariableDeclarator => {
889+
return ast.variableDeclarator(target.id, treeify(target.init!) as es.Expression)
890+
},
898891

899-
IfStatement: (target: es.IfStatement): es.IfStatement => {
900-
return ast.ifStatement(
901-
treeify(target.test) as es.Expression,
902-
treeify(target.consequent) as es.BlockStatement,
903-
treeify(target.alternate!) as es.BlockStatement | es.IfStatement
904-
)
905-
},
892+
IfStatement: (target: es.IfStatement): es.IfStatement => {
893+
return ast.ifStatement(
894+
treeify(target.test) as es.Expression,
895+
treeify(target.consequent) as es.BlockStatement,
896+
treeify(target.alternate!) as es.BlockStatement | es.IfStatement
897+
)
898+
},
906899

907-
// CORE
908-
ArrowFunctionExpression: (target: es.ArrowFunctionExpression): es.Identifier => {
909-
return ast.identifier('=>')
910-
}
911-
}
900+
// CORE
901+
ArrowFunctionExpression: (target: es.ArrowFunctionExpression): es.Identifier => {
902+
return ast.identifier('=>')
903+
},
912904

913-
function treeify(target: substituterNodes): substituterNodes {
914-
const treeifier = treeifiers[target.type]
915-
if (treeifier === undefined) {
916-
return target
917-
} else {
918-
return treeifier(target)
919-
}
905+
// source 2
906+
ArrayExpression: (target: es.ArrayExpression): es.ArrayExpression => {
907+
return ast.arrayExpression(target.elements.map(treeify) as es.Expression[])
920908
}
909+
}
921910

922-
return treeify(program) as es.Program
911+
function treeify(target: substituterNodes): substituterNodes {
912+
const treeifier = treeifiers[target.type]
913+
if (treeifier === undefined) {
914+
return target
915+
} else {
916+
return treeifier(target)
917+
}
923918
}
924919

920+
export const codify = (node: substituterNodes): string => generate(treeify(node))
921+
925922
// strategy: we remember how many statements are there originally in program.
926923
// since listPrelude are just functions, they will be disposed of one by one
927924
// we prepend the program with the program resulting from the definitions,
@@ -931,9 +928,9 @@ export function treeifyMain(program: es.Program): es.Program {
931928
function substPredefinedFns(program: es.Program, context: Context): [es.Program, Context] {
932929
const originalStatementCount = program.body.length
933930
let combinedProgram = program
934-
if (context.chapter >= 2) {
931+
if (context.prelude) {
935932
// evaluate the list prelude first
936-
const listPreludeProgram = parse(listPrelude, context)!
933+
const listPreludeProgram = parse(context.prelude, context)!
937934
combinedProgram.body = listPreludeProgram.body.concat(program.body)
938935
}
939936
while (combinedProgram.body.length > originalStatementCount) {
@@ -950,30 +947,37 @@ export function getEvaluationSteps(program: es.Program, context: Context): subst
950947
try {
951948
// starts with substituting predefined fns.
952949
let [reduced] = substPredefinedFns(program, context) as [substituterNodes, Context]
953-
// let programString = generate(treeifyMain(reduced as es.Program))
950+
let programString = codify(reduced)
954951
while ((reduced as es.Program).body.length > 0) {
952+
if (steps.length === 19999) {
953+
steps.push(
954+
ast.program([ast.expressionStatement(ast.identifier('Maximum number of steps exceeded'))])
955+
)
956+
break
957+
}
955958
steps.push(reduced)
956959
// some bug with no semis
957960
// tslint:disable-next-line
958961
;[reduced] = reduce(reduced, context)
959-
// programString = generate(treeifyMain(reduced as es.Program))
960-
// console.log(programString)
962+
programString = codify(reduced)
963+
console.log(programString)
961964
}
962965
return steps
963966
} catch (error) {
967+
console.log(error)
964968
context.errors.push(error)
965969
return steps
966970
}
967971
}
968972

969-
// function debug() {
970-
// const code = `
971-
// if (true || false) { 1; } else {2;}
972-
// `
973-
// const context = createContext(2)
974-
// const program = parse(code, context)
975-
// const steps = getEvaluationSteps(program!, context)
976-
// return steps.map(treeifyMain).map(generate)
977-
// }
978-
979-
// debug()
973+
function debug() {
974+
const code = `
975+
map(x=>x+1, list(1,2,3));
976+
`
977+
const context = createContext(2)
978+
const program = parse(code, context)
979+
const steps = getEvaluationSteps(program!, context)
980+
return steps.map(treeify).map(generate)
981+
}
982+
983+
debug()

0 commit comments

Comments
 (0)