Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- include "string";
- /*
- extern func println( string str );
- template< typename T > array
- {
- T* m_data;
- int m_size;
- int m_mem;
- operator [] ( int index ) : T
- {
- if( index < 0 || index >= m_size )
- {
- WARNING( "array index out of bounds" );
- return T();
- }
- return m_data[ index ];
- }
- };
- func main( array<string> args )
- {
- for( i = 0; i < args.size; ++i )
- println( args[ i ] );
- println( "Hello, world! (" $ args.size $ ")" );
- }
- func _test()
- {
- main( [ "array", "data", "test" ] );
- }
- */
- /*
- PROBLEMS
- > efficient local variable encoding
- - 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)
- - { type = "scope", locals = [{ name = "one", type = "string" }, { name = "b", type = "int" }], code = [..] },
- - locals are added to stack and accessed by their index
- IDEAS
- > WARNING arguments:
- - string specific - the case-specific error part ("15 outside [0;7]")
- - optional string generic - the error group part ("array index out of bounds")
- - optional string category - the error category path ("RangeError/OutOfBounds")
- */
- global AST =
- {
- "string*" = { type = "pointer", datatype = "string" },
- "array<string>" =
- {
- type = "object",
- classname = "array",
- fullname = "array<string>",
- members =
- [
- { name = "m_data", type = "string*" },
- { name = "m_size", type = "int" },
- { name = "m_mem", type = "int" },
- ],
- static = [],
- },
- "array<string>:[](int)" =
- {
- type = "function",
- retntype = "string",
- params =
- [
- { name = "index", type = "int" },
- ],
- locals = [],
- code =
- [
- { type = "if",
- test = { type = "or",
- lft = { type = "lt", datatype = "int", lft = { type = "local", off = 0 }, rgt = { type = "data", datatype = "int", data = 0 } },
- rgt = { type = "gte", datatype = "int", lft = { type = "local", off = 0 }, rgt = { type = "getmember", name = "m_size" } },
- },
- locals_ontrue = [],
- locals_onfalse = [],
- ontrue =
- [
- { type = "fcall", func = "WARNING", ctx = null, args = [{ type = "data", datatype = "string", data = "array index out of bounds" }] },
- { type = "return", arg = { type = "data", datatype = "string", data = "" } },
- ],
- onfalse = [],
- },
- { type = "return", arg = { type = "getindex", object = { type = "getmember", name = "m_data" }, index = { type = "local", off = 0 } } },
- ],
- },
- "array<string>:size.get" = { type = "getter", retntype = "int", source = "m_size" },
- "array<string>:clear()" =
- {
- type = "function",
- retntype = "void",
- params = [],
- locals = [],
- code =
- [
- { type = "fcall", func = "array<string>:resize(int)", ctx = null, args = [{ type = "data", datatype = "int", data = 0 }] },
- ],
- },
- "println(string)" = { type = "external", func = println, retntype = "void", params = [{ name = "str", type = "string" }] },
- "main(array<string>)" =
- {
- type = "function",
- retntype = "void",
- params =
- [
- { name = "args", type = "array<string>" },
- ],
- locals = [],
- code =
- [
- { type = "for",
- init = { type = "setlocal", datatype = "int", off = 1, value = { type = "data", datatype = "int", data = 0 } },
- test = { type = "lt", datatype = "int",
- lft = { type = "local", off = 1 },
- rgt = { type = "getprop", object = { type = "local", off = 0 }, property = { type = "data", datatype = "string", data = "size" } }
- },
- next = { type = "setlocal", datatype = "int", off = 1, value = { type = "add", datatype = "int",
- lft = { type = "local", off = 1 },
- rgt = { type = "data", datatype = "int", data = 1 } }
- },
- locals = [{ name = "i", type = "int" }],
- body =
- [
- { type = "fcall", func = "println(string)", ctx = null, args = [{ type = "getindex", object = { type = "local", off = 0 }, index = { type = "local", off = 1 } }] },
- ]
- },
- { type = "fcall", func = "println(string)", ctx = null, args =
- [
- { type = "concat", args =
- [
- { type = "data", datatype = "string", data = "Hello, world! (" },
- { type = "convert", datatype = "string", source = { type = "getprop", object = { type = "local", off = 0 }, property = { type = "data", datatype = "string", data = "size" } } },
- { type = "data", datatype = "string", data = ")" },
- ]},
- ]},
- ],
- },
- "_test()" =
- {
- type = "function",
- retntype = "void",
- params = [],
- locals = [],
- code =
- [
- { type = "fcall", func = "main(array<string>)", ctx = null, args =
- [
- { type = "data", datatype = "array<string>", data =
- {
- m_data =
- [
- { type = "string", data = "array" },
- { type = "string", data = "data" },
- { type = "string", data = "test" }
- ],
- m_size = { type = "int", data = 3 },
- m_mem = { type = "int", data = 3 },
- }},
- ]},
- ],
- },
- };
- function resolve_type( typename )
- {
- tydata = @AST[ typename ];
- if( tydata )
- return tydata;
- if( typename != "int" && typename != "string" )
- return ERROR( "no such type: " $ typename );
- return { type = typename };
- }
- function value_is_nonzero( value )
- {
- if( !value )
- return false;
- if( value.type == "bool" )
- return value.data;
- if( value.type == "int" )
- return value.data != 0;
- if( value.type == "string" )
- return value.data.size != 0;
- return true;
- }
- global CALL_STACK = [];
- function do__push_locals( locals )
- {
- outlocals = CALL_STACK.last.locals;
- foreach( local : locals )
- outlocals.push({ name = local.name, type = local.type, data = null });
- }
- function do__pop_locals( locals )
- {
- for( i = 0; i < locals.size; ++i )
- CALL_STACK.last.locals.pop();
- }
- function do_fcall( func, ctx, args )
- {
- fndata = @AST[ func ];
- if( !fndata )
- return WARNING( "function was not found: " $ func );
- if( fndata.type == "external" )
- {
- argsdata = [];
- foreach( carg : args )
- argsdata.push( carg.data );
- fndata.func.apply( ctx, argsdata );
- }
- else
- {
- CALL_STACK.push
- ({
- name = func,
- func = fndata,
- ctx = ctx,
- locals = [],
- retn = false,
- });
- do__push_locals( fndata.params );
- foreach( i, arg : args )
- CALL_STACK.last.locals[ i ].data = arg;
- do__push_locals( fndata.locals );
- foreach( line : fndata.code )
- {
- do_item( line );
- }
- return CALL_STACK.pop().retn;
- }
- }
- function vm_is_a( type, what )
- {
- return type == what;
- }
- function do_concat( args )
- {
- out = "";
- foreach( arg : args )
- {
- arg = do_item( arg );
- if( !vm_is_a( arg.type, "string" ) )
- ERROR( "CONCAT argument " $ arg $ " is not a string" );
- out $= arg.data;
- }
- return { type = "string", data = out };
- }
- function do_getprop( obj, prop )
- {
- if( prop.type != "string" )
- return WARNING( "property has invalid type: " $ prop );
- typeinfo = resolve_type( obj.type );
- key = typeinfo.fullname $ ":" $ prop.data $ ".get";
- fndata = @AST[ key ];
- if( fndata )
- {
- if( fndata.type == "getter" )
- return obj.data[ fndata.source ];
- if( fndata.type == "function" )
- return do_fcall( key, obj, [] );
- }
- foreach( name, val : obj.data )
- {
- if( name == prop.data )
- return val;
- }
- WARNING( "unknown property " $ prop $ " for object " $ obj );
- }
- function do_getindex( obj, idx )
- {
- // special case: pointers
- if( is_array( obj ) )
- {
- return obj[ idx.data ];
- }
- typeinfo = resolve_type( obj.type );
- key = typeinfo.fullname $ ":[](" $ idx.type $ ")";
- fndata = @AST[ key ];
- if( fndata )
- {
- if( fndata.type == "function" )
- return do_fcall( key, obj, [ idx ] );
- }
- WARNING( "unknown index " $ idx $ " for object " $ obj );
- }
- function do_convert( item, typeto )
- {
- if( item.type == typeto )
- return item;
- if( typeto == "string" )
- {
- return { type = "string", data = tostring( item.data ) };
- }
- ERROR( "don't know how to convert from " $ item.type $ " to " $ typeto );
- }
- function do_add( lft, rgt )
- {
- lft = do_item( lft );
- rgt = do_item( rgt );
- if( lft.type == "int" && rgt.type == "int" )
- return { type = "int", data = lft.data + rgt.data };
- ERROR( "don't know how to do 'add' on this type" );
- }
- function do_lt( lft, rgt )
- {
- lft = do_item( lft );
- rgt = do_item( rgt );
- if( lft.type == "int" && rgt.type == "int" )
- return { type = "bool", data = lft.data < rgt.data };
- ERROR( "don't know how to do 'lt' on this type" );
- }
- function do_gte( lft, rgt )
- {
- lft = do_item( lft );
- rgt = do_item( rgt );
- if( lft.type == "int" && rgt.type == "int" )
- return { type = "bool", data = lft.data >= rgt.data };
- ERROR( "don't know how to do 'gte' on this type" );
- }
- function do_or( lft, rgt )
- {
- if( value_is_nonzero( do_item( lft ) ) )
- return true;
- return value_is_nonzero( do_item( rgt ) );
- }
- function do_item( item )
- {
- if( !item )
- return;
- if( CALL_STACK.last.retn )
- return;
- println( string_repeat( " ", 40 ) $ "doing " $ item.type $ " in " $ CALL_STACK.last.name );
- if( item.type == "data" )
- return { type = item.datatype, data = item.data };
- if( item.type == "local" )
- {
- local = CALL_STACK.last.locals[ item.off ];
- println( string_repeat( " ", 30 ) $ "reading local " $ local.name $ "@" $ item.off $ " = " $ local.data );
- return local.data;
- }
- if( item.type == "setlocal" )
- {
- local = CALL_STACK.last.locals[ item.off ];
- value = do_item( item.value );
- println( string_repeat( " ", 30 ) $ "writing local " $ local.name $ "@" $ item.off $ " = " $ value );
- return local.data = value;
- }
- if( item.type == "convert" )
- {
- return do_convert( do_item( item.source ), item.datatype );
- }
- if( item.type == "if" )
- {
- if( value_is_nonzero( do_item( item.test ) ) )
- {
- do__push_locals( item.locals_ontrue );
- foreach( line : item.ontrue )
- do_item( line );
- do__pop_locals( item.locals_ontrue );
- }
- else
- {
- do__push_locals( item.locals_onfalse );
- foreach( line : item.onfalse )
- do_item( line );
- do__pop_locals( item.locals_onfalse );
- }
- return;
- }
- if( item.type == "for" )
- {
- do__push_locals( item.locals );
- do_item( item.init );
- while( value_is_nonzero( do_item( item.test ) ) )
- {
- foreach( line : item.body )
- do_item( line );
- do_item( item.next );
- }
- do__pop_locals( item.locals );
- return;
- }
- if( item.type == "fcall" )
- {
- args = [];
- foreach( arg : item.args )
- args.push( do_item( arg ) );
- return do_fcall( item.func, do_item( item.ctx ), args );
- }
- if( item.type == "return" )
- {
- CALL_STACK.last.retn = if( @item.arg, do_item( item.arg ), true );
- return;
- }
- if( item.type == "concat" )
- return do_concat( item.args );
- if( item.type == "getprop" ) return do_getprop( do_item( item.object ), do_item( item.property ) );
- if( item.type == "getmember" ) return do_getprop( CALL_STACK.last.ctx, { type = "string", data = item.name } );
- if( item.type == "getindex" ) return do_getindex( do_item( item.object ), do_item( item.index ) );
- if( item.type == "add" ) return do_add( item.lft, item.rgt );
- if( item.type == "lt" ) return do_lt( item.lft, item.rgt );
- if( item.type == "gte" ) return do_gte( item.lft, item.rgt );
- if( item.type == "or" ) return do_or( item.lft, item.rgt );
- ERROR( "cannot do action " $ item.type );
- }
- do_fcall( "_test()", null, [] );
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement