1
- // import { generate } from 'astring'
1
+ import { generate } from 'astring'
2
2
import * as es from 'estree'
3
- // import createContext from './createContext'
3
+ import createContext from './createContext'
4
4
import * as errors from './interpreter-errors'
5
5
import { parse } from './parser'
6
- import { listPrelude } from './stdlib/list.prelude'
7
6
import { BlockExpression , Context , FunctionDeclarationExpression , substituterNodes } from './types'
8
7
import * as ast from './utils/astCreator'
9
8
import {
@@ -16,6 +15,7 @@ import {
16
15
} from './utils/dummyAstCreator'
17
16
import { evaluateBinaryExpression , evaluateUnaryExpression } from './utils/operators'
18
17
import * as rttc from './utils/rttc'
18
+ import * as builtin from './utils/substituter'
19
19
20
20
const irreducibleTypes = new Set < string > ( [
21
21
'Identifier' ,
@@ -52,17 +52,7 @@ function substituteMain(
52
52
) : es . Identifier | FunctionDeclarationExpression | es . Literal | es . Expression {
53
53
if ( replacement . type === 'Literal' ) {
54
54
// 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
66
56
} else {
67
57
return target . name === name . name
68
58
? ( substitute ( replacement ) as FunctionDeclarationExpression )
@@ -248,6 +238,13 @@ function substituteMain(
248
238
? ( substitute ( target . alternate ) as es . BlockStatement )
249
239
: null
250
240
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
251
248
}
252
249
}
253
250
@@ -324,12 +321,7 @@ const reducers = {
324
321
325
322
ExpressionStatement ( node : es . ExpressionStatement , context : Context ) : [ substituterNodes , Context ] {
326
323
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 ]
333
325
} ,
334
326
335
327
BinaryExpression ( node : es . BinaryExpression , context : Context ) : [ substituterNodes , Context ] {
@@ -499,15 +491,17 @@ const reducers = {
499
491
}
500
492
}
501
493
// 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
+ }
511
505
}
512
506
} ,
513
507
@@ -822,106 +816,109 @@ function reduce(node: substituterNodes, context: Context): [substituterNodes, Co
822
816
}
823
817
}
824
818
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
+ } ,
835
828
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
+ } ,
843
836
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
+ } ,
847
840
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
+ } ,
855
848
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
+ } ,
862
855
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
+ } ,
868
861
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
+ } ,
873
866
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
+ } ,
877
870
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
+ } ,
881
874
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
+ } ,
885
878
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
+ } ,
889
882
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
+ } ,
894
887
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
+ } ,
898
891
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
+ } ,
906
899
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
+ } ,
912
904
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 [ ] )
920
908
}
909
+ }
921
910
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
+ }
923
918
}
924
919
920
+ export const codify = ( node : substituterNodes ) : string => generate ( treeify ( node ) )
921
+
925
922
// strategy: we remember how many statements are there originally in program.
926
923
// since listPrelude are just functions, they will be disposed of one by one
927
924
// we prepend the program with the program resulting from the definitions,
@@ -931,9 +928,9 @@ export function treeifyMain(program: es.Program): es.Program {
931
928
function substPredefinedFns ( program : es . Program , context : Context ) : [ es . Program , Context ] {
932
929
const originalStatementCount = program . body . length
933
930
let combinedProgram = program
934
- if ( context . chapter >= 2 ) {
931
+ if ( context . prelude ) {
935
932
// evaluate the list prelude first
936
- const listPreludeProgram = parse ( listPrelude , context ) !
933
+ const listPreludeProgram = parse ( context . prelude , context ) !
937
934
combinedProgram . body = listPreludeProgram . body . concat ( program . body )
938
935
}
939
936
while ( combinedProgram . body . length > originalStatementCount ) {
@@ -950,30 +947,37 @@ export function getEvaluationSteps(program: es.Program, context: Context): subst
950
947
try {
951
948
// starts with substituting predefined fns.
952
949
let [ reduced ] = substPredefinedFns ( program , context ) as [ substituterNodes , Context ]
953
- // let programString = generate(treeifyMain( reduced as es.Program) )
950
+ let programString = codify ( reduced )
954
951
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
+ }
955
958
steps . push ( reduced )
956
959
// some bug with no semis
957
960
// tslint:disable-next-line
958
961
; [ reduced ] = reduce ( reduced , context )
959
- // programString = generate(treeifyMain( reduced as es.Program) )
960
- // console.log(programString)
962
+ programString = codify ( reduced )
963
+ console . log ( programString )
961
964
}
962
965
return steps
963
966
} catch ( error ) {
967
+ console . log ( error )
964
968
context . errors . push ( error )
965
969
return steps
966
970
}
967
971
}
968
972
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