Advertisement
snake5

new lang ast proto on sgs

Dec 21st, 2014
558
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. include "string";
  3.  
  4. /*
  5. extern func println( string str );
  6. template< typename T > array
  7. {
  8.     T* m_data;
  9.     int m_size;
  10.     int m_mem;
  11.    
  12.     operator [] ( int index ) : T
  13.     {
  14.         if( index < 0 || index >= m_size )
  15.         {
  16.             WARNING( "array index out of bounds" );
  17.             return T();
  18.         }
  19.         return m_data[ index ];
  20.     }
  21. };
  22. func main( array<string> args )
  23. {
  24.     for( i = 0; i < args.size; ++i )
  25.         println( args[ i ] );
  26.     println( "Hello, world! (" $ args.size $ ")" );
  27. }
  28. func _test()
  29. {
  30.     main( [ "array", "data", "test" ] );
  31. }
  32. */
  33.  
  34. /*
  35. PROBLEMS
  36.  
  37. > efficient local variable encoding
  38. - all local variables have a scope but name should not be duplicated or resolved, we can use an offset table at most (padding could be arch-dependent)
  39. - { type = "scope", locals = [{ name = "one", type = "string" }, { name = "b", type = "int" }], code = [..] },
  40. - locals are added to stack and accessed by their index
  41.  
  42.  
  43. IDEAS
  44.  
  45. > WARNING arguments:
  46. - string specific - the case-specific error part ("15 outside [0;7]")
  47. - optional string generic - the error group part ("array index out of bounds")
  48. - optional string category - the error category path ("RangeError/OutOfBounds")
  49.  
  50. */
  51.  
  52. global AST =
  53. {
  54.     "string*" = { type = "pointer", datatype = "string" },
  55.     "array<string>" =
  56.     {
  57.         type = "object",
  58.         classname = "array",
  59.         fullname = "array<string>",
  60.         members =
  61.         [
  62.             { name = "m_data", type = "string*" },
  63.             { name = "m_size", type = "int" },
  64.             { name = "m_mem", type = "int" },
  65.         ],
  66.         static = [],
  67.     },
  68.     "array<string>:[](int)" =
  69.     {
  70.         type = "function",
  71.         retntype = "string",
  72.         params =
  73.         [
  74.             { name = "index", type = "int" },
  75.         ],
  76.         locals = [],
  77.         code =
  78.         [
  79.             { type = "if",
  80.                 test = { type = "or",
  81.                     lft = { type = "lt", datatype = "int", lft = { type = "local", off = 0 }, rgt = { type = "data", datatype = "int", data = 0 } },
  82.                     rgt = { type = "gte", datatype = "int", lft = { type = "local", off = 0 }, rgt = { type = "getmember", name = "m_size" } },
  83.                 },
  84.                 locals_ontrue = [],
  85.                 locals_onfalse = [],
  86.                 ontrue =
  87.                 [
  88.                     { type = "fcall", func = "WARNING", ctx = null, args = [{ type = "data", datatype = "string", data = "array index out of bounds" }] },
  89.                     { type = "return", arg = { type = "data", datatype = "string", data = "" } },
  90.                 ],
  91.                 onfalse = [],
  92.             },
  93.             { type = "return", arg = { type = "getindex", object = { type = "getmember", name = "m_data" }, index = { type = "local", off = 0 } } },
  94.         ],
  95.     },
  96.     "array<string>:size.get" = { type = "getter", retntype = "int", source = "m_size" },
  97.     "array<string>:clear()" =
  98.     {
  99.         type = "function",
  100.         retntype = "void",
  101.         params = [],
  102.         locals = [],
  103.         code =
  104.         [
  105.             { type = "fcall", func = "array<string>:resize(int)", ctx = null, args = [{ type = "data", datatype = "int", data = 0 }] },
  106.         ],
  107.     },
  108.     "println(string)" = { type = "external", func = println, retntype = "void", params = [{ name = "str", type = "string" }] },
  109.     "main(array<string>)" =
  110.     {
  111.         type = "function",
  112.         retntype = "void",
  113.         params =
  114.         [
  115.             { name = "args", type = "array<string>" },
  116.         ],
  117.         locals = [],
  118.         code =
  119.         [
  120.             { type = "for",
  121.                 init = { type = "setlocal", datatype = "int", off = 1, value = { type = "data", datatype = "int", data = 0 } },
  122.                 test = { type = "lt", datatype = "int",
  123.                     lft = { type = "local", off = 1 },
  124.                     rgt = { type = "getprop", object = { type = "local", off = 0 }, property = { type = "data", datatype = "string", data = "size" } }
  125.                 },
  126.                 next = { type = "setlocal", datatype = "int", off = 1, value = { type = "add", datatype = "int",
  127.                     lft = { type = "local", off = 1 },
  128.                     rgt = { type = "data", datatype = "int", data = 1 } }
  129.                 },
  130.                 locals = [{ name = "i", type = "int" }],
  131.                 body =
  132.                 [
  133.                     { type = "fcall", func = "println(string)", ctx = null, args = [{ type = "getindex", object = { type = "local", off = 0 }, index = { type = "local", off = 1 } }] },
  134.                 ]
  135.             },
  136.             { type = "fcall", func = "println(string)", ctx = null, args =
  137.             [
  138.                 { type = "concat", args =
  139.                 [
  140.                     { type = "data", datatype = "string", data = "Hello, world! (" },
  141.                     { type = "convert", datatype = "string", source = { type = "getprop", object = { type = "local", off = 0 }, property = { type = "data", datatype = "string", data = "size" } } },
  142.                     { type = "data", datatype = "string", data = ")" },
  143.                 ]},
  144.             ]},
  145.         ],
  146.     },
  147.     "_test()" =
  148.     {
  149.         type = "function",
  150.         retntype = "void",
  151.         params = [],
  152.         locals = [],
  153.         code =
  154.         [
  155.             { type = "fcall", func = "main(array<string>)", ctx = null, args =
  156.             [
  157.                 { type = "data", datatype = "array<string>", data =
  158.                 {
  159.                     m_data =
  160.                     [
  161.                         { type = "string", data = "array" },
  162.                         { type = "string", data = "data" },
  163.                         { type = "string", data = "test" }
  164.                     ],
  165.                     m_size = { type = "int", data = 3 },
  166.                     m_mem = { type = "int", data = 3 },
  167.                 }},
  168.             ]},
  169.         ],
  170.     },
  171. };
  172.  
  173.  
  174.  
  175. function resolve_type( typename )
  176. {
  177.     tydata = @AST[ typename ];
  178.     if( tydata )
  179.         return tydata;
  180.     if( typename != "int" && typename != "string" )
  181.         return ERROR( "no such type: " $ typename );
  182.     return { type = typename };
  183. }
  184.  
  185. function value_is_nonzero( value )
  186. {
  187.     if( !value )
  188.         return false;
  189.     if( value.type == "bool" )
  190.         return value.data;
  191.     if( value.type == "int" )
  192.         return value.data != 0;
  193.     if( value.type == "string" )
  194.         return value.data.size != 0;
  195.     return true;
  196. }
  197.  
  198. global CALL_STACK = [];
  199.  
  200. function do__push_locals( locals )
  201. {
  202.     outlocals = CALL_STACK.last.locals;
  203.     foreach( local : locals )
  204.         outlocals.push({ name = local.name, type = local.type, data = null });
  205. }
  206.  
  207. function do__pop_locals( locals )
  208. {
  209.     for( i = 0; i < locals.size; ++i )
  210.         CALL_STACK.last.locals.pop();
  211. }
  212.  
  213. function do_fcall( func, ctx, args )
  214. {
  215.     fndata = @AST[ func ];
  216.     if( !fndata )
  217.         return WARNING( "function was not found: " $ func );
  218.    
  219.     if( fndata.type == "external" )
  220.     {
  221.         argsdata = [];
  222.         foreach( carg : args )
  223.             argsdata.push( carg.data );
  224.         fndata.func.apply( ctx, argsdata );
  225.     }
  226.     else
  227.     {
  228.         CALL_STACK.push
  229.         ({
  230.             name = func,
  231.             func = fndata,
  232.             ctx = ctx,
  233.             locals = [],
  234.             retn = false,
  235.         });
  236.         do__push_locals( fndata.params );
  237.         foreach( i, arg : args )
  238.             CALL_STACK.last.locals[ i ].data = arg;
  239.         do__push_locals( fndata.locals );
  240.         foreach( line : fndata.code )
  241.         {
  242.             do_item( line );
  243.         }
  244.         return CALL_STACK.pop().retn;
  245.     }
  246. }
  247.  
  248. function vm_is_a( type, what )
  249. {
  250.     return type == what;
  251. }
  252.  
  253. function do_concat( args )
  254. {
  255.     out = "";
  256.     foreach( arg : args )
  257.     {
  258.         arg = do_item( arg );
  259.         if( !vm_is_a( arg.type, "string" ) )
  260.             ERROR( "CONCAT argument " $ arg $ " is not a string" );
  261.         out $= arg.data;
  262.     }
  263.     return { type = "string", data = out };
  264. }
  265.  
  266. function do_getprop( obj, prop )
  267. {
  268.     if( prop.type != "string" )
  269.         return WARNING( "property has invalid type: " $ prop );
  270.    
  271.     typeinfo = resolve_type( obj.type );
  272.     key = typeinfo.fullname $ ":" $ prop.data $ ".get";
  273.     fndata = @AST[ key ];
  274.     if( fndata )
  275.     {
  276.         if( fndata.type == "getter" )
  277.             return obj.data[ fndata.source ];
  278.         if( fndata.type == "function" )
  279.             return do_fcall( key, obj, [] );
  280.     }
  281.     foreach( name, val : obj.data )
  282.     {
  283.         if( name == prop.data )
  284.             return val;
  285.     }
  286.    
  287.     WARNING( "unknown property " $ prop $ " for object " $ obj );
  288. }
  289.  
  290. function do_getindex( obj, idx )
  291. {
  292.     // special case: pointers
  293.     if( is_array( obj ) )
  294.     {
  295.         return obj[ idx.data ];
  296.     }
  297.    
  298.     typeinfo = resolve_type( obj.type );
  299.     key = typeinfo.fullname $ ":[](" $ idx.type $ ")";
  300.     fndata = @AST[ key ];
  301.     if( fndata )
  302.     {
  303.         if( fndata.type == "function" )
  304.             return do_fcall( key, obj, [ idx ] );
  305.     }
  306.    
  307.     WARNING( "unknown index " $ idx $ " for object " $ obj );
  308. }
  309.  
  310. function do_convert( item, typeto )
  311. {
  312.     if( item.type == typeto )
  313.         return item;
  314.    
  315.     if( typeto == "string" )
  316.     {
  317.         return { type = "string", data = tostring( item.data ) };
  318.     }
  319.    
  320.     ERROR( "don't know how to convert from " $ item.type $ " to " $ typeto );
  321. }
  322.  
  323. function do_add( lft, rgt )
  324. {
  325.     lft = do_item( lft );
  326.     rgt = do_item( rgt );
  327.     if( lft.type == "int" && rgt.type == "int" )
  328.         return { type = "int", data = lft.data + rgt.data };
  329.     ERROR( "don't know how to do 'add' on this type" );
  330. }
  331.  
  332. function do_lt( lft, rgt )
  333. {
  334.     lft = do_item( lft );
  335.     rgt = do_item( rgt );
  336.     if( lft.type == "int" && rgt.type == "int" )
  337.         return { type = "bool", data = lft.data < rgt.data };
  338.     ERROR( "don't know how to do 'lt' on this type" );
  339. }
  340.  
  341. function do_gte( lft, rgt )
  342. {
  343.     lft = do_item( lft );
  344.     rgt = do_item( rgt );
  345.     if( lft.type == "int" && rgt.type == "int" )
  346.         return { type = "bool", data = lft.data >= rgt.data };
  347.     ERROR( "don't know how to do 'gte' on this type" );
  348. }
  349.  
  350. function do_or( lft, rgt )
  351. {
  352.     if( value_is_nonzero( do_item( lft ) ) )
  353.         return true;
  354.     return value_is_nonzero( do_item( rgt ) );
  355. }
  356.  
  357. function do_item( item )
  358. {
  359.     if( !item )
  360.         return;
  361.    
  362.     if( CALL_STACK.last.retn )
  363.         return;
  364.    
  365.     println( string_repeat( " ", 40 ) $ "doing " $ item.type $ " in " $ CALL_STACK.last.name );
  366.     if( item.type == "data" )
  367.         return { type = item.datatype, data = item.data };
  368.     if( item.type == "local" )
  369.     {
  370.         local = CALL_STACK.last.locals[ item.off ];
  371.         println( string_repeat( " ", 30 ) $ "reading local " $ local.name $ "@" $ item.off $ " = " $ local.data );
  372.         return local.data;
  373.     }
  374.     if( item.type == "setlocal" )
  375.     {
  376.         local = CALL_STACK.last.locals[ item.off ];
  377.         value = do_item( item.value );
  378.         println( string_repeat( " ", 30 ) $ "writing local " $ local.name $ "@" $ item.off $ " = " $ value );
  379.         return local.data = value;
  380.     }
  381.     if( item.type == "convert" )
  382.     {
  383.         return do_convert( do_item( item.source ), item.datatype );
  384.     }
  385.     if( item.type == "if" )
  386.     {
  387.         if( value_is_nonzero( do_item( item.test ) ) )
  388.         {
  389.             do__push_locals( item.locals_ontrue );
  390.             foreach( line : item.ontrue )
  391.                 do_item( line );
  392.             do__pop_locals( item.locals_ontrue );
  393.         }
  394.         else
  395.         {
  396.             do__push_locals( item.locals_onfalse );
  397.             foreach( line : item.onfalse )
  398.                 do_item( line );
  399.             do__pop_locals( item.locals_onfalse );
  400.         }
  401.         return;
  402.     }
  403.     if( item.type == "for" )
  404.     {
  405.         do__push_locals( item.locals );
  406.         do_item( item.init );
  407.         while( value_is_nonzero( do_item( item.test ) ) )
  408.         {
  409.             foreach( line : item.body )
  410.                 do_item( line );
  411.             do_item( item.next );
  412.         }
  413.         do__pop_locals( item.locals );
  414.         return;
  415.     }
  416.     if( item.type == "fcall" )
  417.     {
  418.         args = [];
  419.         foreach( arg : item.args )
  420.             args.push( do_item( arg ) );
  421.         return do_fcall( item.func, do_item( item.ctx ), args );
  422.     }
  423.     if( item.type == "return" )
  424.     {
  425.         CALL_STACK.last.retn = if( @item.arg, do_item( item.arg ), true );
  426.         return;
  427.     }
  428.     if( item.type == "concat" )
  429.         return do_concat( item.args );
  430.    
  431.     if( item.type == "getprop" ) return do_getprop( do_item( item.object ), do_item( item.property ) );
  432.     if( item.type == "getmember" ) return do_getprop( CALL_STACK.last.ctx, { type = "string", data = item.name } );
  433.     if( item.type == "getindex" ) return do_getindex( do_item( item.object ), do_item( item.index ) );
  434.    
  435.     if( item.type == "add" ) return do_add( item.lft, item.rgt );
  436.    
  437.     if( item.type == "lt" ) return do_lt( item.lft, item.rgt );
  438.     if( item.type == "gte" ) return do_gte( item.lft, item.rgt );
  439.    
  440.     if( item.type == "or" ) return do_or( item.lft, item.rgt );
  441.    
  442.     ERROR( "cannot do action " $ item.type );
  443. }
  444.  
  445.  
  446. do_fcall( "_test()", null, [] );
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement