// This is Jarkko Kniivilä (jkniiv ät gmail.com) trying to grok OMeta and make a Limbo language translator. // This project is inspired by the JavaScript_Compiler parser and translator. Most of the parser is a // straightforward mapping of the Limbo language definition BNF, only the prioritization of rules is changed. ometa LimboParser <: Parser { fromTo :x :y = seq(x) (~seq(y) char)* seq(y), hexDigit = char:x {this.hexDigits.indexOf(x.toLowerCase())}:v ?(v >= 0) -> v, hexLiteral = hexLiteral:n hexDigit:d -> (n * 16 + d) | hexDigit, number = spaces ``0x'' hexLiteral:n -> [`number, n] | spaces digit+:ws ('.' digit+ | empty -> []):fs -> [`number, parseFloat(ws.join('') + '.' + fs.join(''))], escapeChar = '\\' char:c -> unescape('\\' + c), plainStringConstant = '"' (escapeChar | ~'"' char)*:cs '"' -> [`stringCon, cs.join('')], stringConstant = spaces plainStringConstant, nil = "nil" -> [`nil], identifierFirst = '_' | letter, identifierRest = identifierFirst | digit, plainIdentifier = firstAndRest(`identifierFirst, `identifierRest):xs -> xs.join(''), identifier = spaces plainIdentifier:t -> [`nm, t], identifier_opt = identifier | (empty -> [`empty]), identifierList = listOf(`identifier, ','):xs -> [`nmList].concat(xs), program = "implement" identifier:n ";" topDeclarationSequence:xs -> [`program, n, xs], topDeclarationSequence = listOf(`topDeclaration, ''):xs -> [`topDeclSeq].concat(xs), topDeclaration = declaration | identifierList:xs ":=" expression:x ";" -> ["top:=", xs, x] | identifierList:xs "=" expression:x ";" -> ["top=", xs, x] | "(" identifierList:xs ")" ":=" expression:x ";" -> ["topTuple:=", xs, x] | moduleDeclaration | functionDefinition | adtDeclaration, declaration = identifierList:xs ":" "con" expression:x ";" -> [`declCon, xs, x] | identifierList:xs ":" "import" identifier:x ";" -> [`declImport, xs, nm] | identifierList:xs ":" "type" type:t ";" -> [`declType, xs, t] | identifierList:xs ":" type:t "=" expression:x ";" -> [`declVal, xs, t, x] | identifierList:xs ":" type:t ";" -> [`declSimple, xs, t] | "include" stringConstant:filename ";" -> [`include, filename], expressionList = listOf(`expression, ','):xs -> [`exprList].concat(xs), expressionList_opt = expressionList | empty, type = functionType | dataType, dataType = ("byte" | "int" | "big" | "real" | "string"):t -> [`type, t] | tupleType | "array" "of" dataType:t -> [`typeArrayOf, t] | "list" "of" dataType:t -> [`typeListOf, t] | "chan" "of" dataType:t -> [`typeChanOf, t] | "ref" adtType:t -> [`typeRef, t] | adtType | moduleType | moduleQualifiedType | typeName, tupleType = "(" dataTypeList:t ")" -> [`typeTuple, t], dataTypeList = listOf(`dataType, ','):xs -> [`typelist].concat(xs), adtType = moduleQualifiedType | identifier, moduleType = identifier:t -> [`typeMod, t], moduleQualifiedType = identifier:m "->" identifier:t -> [`typeModQual, m, t], typeName = identifier:t -> [`typename, t], functionType = "fn" functionArgRet:t -> [`typeFn, t], functionArgRet = "(" formalArgList:xs ")" ":" dataType:t -> [`argRet, xs, t] | "(" formalArgList:xs ")" -> [`args, xs], formalArgList = listOf(`formalArg, ','):xs -> [`argList].concat(xs), formalArg = nilOrD:x ":" "self" "ref" identifier:y -> [`argSelfRef, x, y] | nilOrD:x ":" "self" identifier:y -> [`argSelf, x, y] | nilOrDList:xs ":" type:t -> [`arg, xs, t] | "*" -> ['arg*'], nilOrDList = listOf(`nilOrD, ','):xs -> [`nilOrDlist].concat(xs), nilOrD = nil | identifier, moduleDeclaration = identifier:x ":" "module" "{" modMemberList:xs "}" ";" -> [`modDecl, x, xs], modMemberList = listOf(`modMember, ''):xs -> [`modMemList].concat(xs), modMember = identifierList:xs ":" functionType:y ";" -> [`modMemFn, xs, y] | adtDeclaration | identifierList:xs ":" "type" type:y ";" -> [`modMemType, xs, y] | identifierList:xs ":" dataType:y ";" -> [`modMemSmpl, xs, y], adtDeclaration = identifier:x ":" "adt" "{" adtMemberList:ys "}" ";" -> [`adtDecl, x, ys], adtMemberList = listOf(`adtMember, ''):xs -> [`adtMemList].concat(xs), adtMember = identifierList:xs ":" functionType:y ";" -> ["adtMemFn", xs, y] | identifierList:xs ":" cyclic:o dataType:y ";" -> ["adtMemSmpl", xs, o, y], cyclic = "cyclic" -> [`cyclic] | empty -> [`empty], functionDefinition = functionNamePart:n functionArgRet:a "{" statements:xs "}" -> [`fnDefn, n, a, xs], functionNamePart = functionNamePart:xs "." identifier:n -> [".", xs, n] | identifier, statements = statements:xs declaration:y -> [xs, "decl::", y] | listOf(`statement, ''):xs -> [`stmtList].concat(xs) | empty, statement = "{" statements:xs "}" -> [`block, xs] | "if" "(" expression:p ")" statement:x "else" statement:y -> [`ifThenElse, p, x, y] | "if" "(" expression:p ")" statement:x -> [`ifThen, p, x] | label_opt:l "while" "(" expression_opt:p ")" statement:x -> [`while, l, p, x] | label_opt:l "do" statement:x "while" "(" expression_opt:p ")" -> [`doWhile, l, x, p] | label_opt:l "for" "(" expression_opt:x ";" expression_opt:p ";" expression_opt:y ")" statement:z -> [`for, l, x, p, y, z] | label_opt:l "case" expression:x "{" qualStatementSequence:ys "}" -> [`case, l, x, ys] | label_opt:l "alt" "{" qualStatementSequence:ys "}" -> [`alt, l, ys] | "break" identifier_opt:n ";" -> [`break, n] | "continue" expression_opt:x ";" -> [`continue, x] | "return" expression_opt:x ";" -> [`return, x] | "spawn" term:fnCall ?(fnCall[0] == 'fnCall') ";" -> [`spawn, fnCall] | "exit" ";" -> [`exit] | expression:xs ";" -> [`stmt, xs] | ";" -> [`emptyStmt], // spawnStatement = "spawn" term:fnCall ?(fnCall[0] == 'fnCall') ";" -> [`spawn, fnCall], label = identifier:l ":" -> [`label, l], label_opt = label | (empty -> [`empty]), qualStatementSequence = qualStatementSequence:xs qualList:ys "=>" -> [`qualSSList, xs, ys] | qualStatementSequence:xs statement:y -> [`qualSSStmt, xs, y] | qualStatementSequence:xs declaration:y -> [`qualSSDecl, xs, y] | qualList:xs "=>" -> [`qualSimple, xs], qualList = listOf(`qualifier, 'or'):xs -> ["qualOr"].concat(xs), qualifier = expression:x "to" expression:y -> ["qualTo", x, y] | expression | "*" -> ["qualStar"], expression = sendExpression | declareExpression | lvalueExpression:l assignmentOperator:op expression:r -> [`set, op, l, r] | binaryExpression | loadExpression, expression_opt = expression | (empty -> [`empty]), binaryExpression = binaryExpression:l binaryOperator:op binaryExpression:r -> [`binOp, op, l, r] | monadicExpression, binaryOperator = "*" | "/" | "%" | "+" | "-" | "<<" | ">>" | "<" | ">" | "<=" | ">=" | "==" | "!=" | "&" | "^" | "|" | "::" | "&&" | "||", assignmentExpression = lvalueExpression:l assignmentOperator:op expression:r -> [`set, op, l, r], assignmentOperator = "=" | "&=" | "|=" | "^=" | "<<=" | ">>=" | "+=" | "-=" | "*=" | "/=" | "%=", lvalueExpression = term:x ?(x[0] == 'index') -> [`lvalue, x] | term:x ?(x[0] == 'sliceBegin') -> [`lvalue, x] | term:x ?(x[0] == 'dot') -> [`lvalue, x] | "nil":x -> [`lvalue, x] | identifier:x -> [`lvalue, x] | "(" listOf(`lvalueExpression, ','):xs ")" -> [`lvalueTuple].concat(xs) | "*" monadicExpression:x -> [`lvalueStar, x], monadicExpression = monadicOperator:op monadicExpression:x -> [`monOp, op, x] | "array" "[" expression:s "]" "of" dataType:t -> [`array, s, t] | "array" "[" expression_opt:s "]" "of" "{" initList:xs "}" -> [`arrayInit, s, xs] | "list" "of" "{" expressionList:xs "}" -> [`list, xs] | "chan" "of" dataType:t -> [`chan, t] | dataType:t ~"(" monadicExpression:x -> [`cast, t, x] | term, term = "(" expressionList:xs ")" -> ["()", xs] | term:x "." identifier:y -> [`dot, x, y] | term:x "->" term:y -> ["->", x, y] | term:fn "(" listOf(`expression, ','):xs ")" -> [`fnCall, fn].concat(xs) | term:x "[" expression:i "]" -> [`index, x, i] | term:x "[" expression:a ":" expression:b "]" -> [`slice, x, a, b] | term:x "[" expression:a ":" "]" -> [`sliceBegin, x, a] | term:x "++" -> [`incr, x] | term:x "--" -> [`decr, x] | "nil" -> [`nil] | stringConstant | number | identifier, functionCall = term:fn "(" listOf(`expression, ','):xs ")" -> [`fnCall, fn].concat(xs), monadicOperator = "+" | "-" | "!" | "~" | "ref" | "*" | "<-" | "hd" | "tl" | "len", initList = listOf(`element, ','):xs -> [`initList].concat(xs), element = expression:x "=>" expression:y -> ["=>", x, y] | "*" "=>" expression:y -> ["*=>", y] | expression, sendExpression = lvalueExpression:l "<-" "=" expression:r -> [`send, l, r], declareExpression = lvalueExpression:l ":=" expression:r -> [":=", l, r], loadExpression = "load" identifier:n expression:x -> [`load, n, x] } LimboParser.hexDigits = "0123456789abcdef" ometa LimboLilScriptParser <: LimboParser { topDeclaration = lilscriptPrototypeDecl | ^topDeclaration, lilscriptPrototypeDecl = "@prototype" identifier:nm lilscriptPrototypeAdtDecl:adt lilscriptPrototypeMemList:members "@end" "prototype" -> [`lsProtoDecl, nm, adt, members], lilscriptPrototypeAdtDecl = "{" adtMemberList:members "}" -> [`lsProtoAdtDecl, members], lilscriptPrototypeMemList = listOf(`lilscriptPrototypeMember, ''):members -> [`lsProtoMemList].concat(members), lilscriptPrototypeMember = "@property" identifierList:names ";" -> [`lsProtoMemProp, names] | "-" lilscriptMethodArgRet:argret ";" -> [`lsProtoMemMthd, argret], lilscriptMethodArgRet = "(" dataType:t ")" lilscriptSelectorFormalArgs:selfargs -> [`lsMethodArgRet, selfargs, t] | lilscriptSelectorFormalArgs:selfargs -> [`lsMethodArgs, selfargs], lilscriptSelectorFormalArgs = lilscriptSelectorFArgPart+:selfargs -> [`lsSelFArgs].concat(selfargs) | identifier:selnm -> [`lsSelUnary, selnm], lilscriptSelectorFArgPart = identifier:selnm ":" lilscriptArgType_opt:t identifier:nm -> [`lsSelFArgPart, selnm, t, nm], lilscriptArgType_opt = "(" dataType:t ")" -> t | (empty -> [`empty]), lilscriptPrototypeImpl = "@complete" identifier:nm lilscriptProtoImplSeq:methods "@end" "complete" -> [`lsProtoImpl, nm, methods], lilscriptProtoImplSeq = listOf(`lilscriptMethodDefinition, ''), lilscriptMethodDefinition = "-" lilscriptMethodArgRet:argret "{" statements:xs "}" -> [`lsMethodDefn, argret, xs], term = "[" lilscriptExpressionList:exprs "]" -> exprs | ^term, lilscriptExpressionList = listOf(`lilscriptExpression, ';'):xs -> [`ls].concat(xs), lilscriptExpression = lilscriptTerm:x listOf(`lilscriptSelector, ','):sels -> [`lsExpr, x].concat(sels) | lilscriptTerm "," , lilscriptSelector = lilscriptPhrase:xs ":" expression:y -> [`lsSel, xs, y] | lilscriptPhrase:xs -> [`lsSel, xs], lilscriptPhrase = listOf(`identifier, ''):xs -> [`lsPhrase].concat(xs), lilscriptTerm = "`" identifier:x -> [`lsBacktickObj, x] | "@" identifier:x -> [`lsAtObj, x] | identifier:x -> [`lsObj, x] | "[" lilscriptExpressionList:exprs "]" -> exprs } ometa LimboTranslator { toplevelTr = [:t {this._applyWithArgs(t, -2)}:ans] -> ans, tr :i = [:t {this._applyWithArgs(t, i + 1)}:ans] -> ans, number :i = :n -> ( n < 0 ? '(' + n + ')' : n ), stringCon :i = :s -> s.toProgramString(), nil :i -> 'nil', nm :i = :x -> x, type :i = :t -> t, nmList :i = tr(i)*:xs -> xs.join(', '), program :i = tr(i):nm tr(i):topdeclseq -> ('implement ' + nm + '\;\n\n' + topdeclseq), topDeclSeq :i = tr(i)*:topdecls -> topdecls.join(''), 'top:=' :i = tr(i):nmlist tr(i):expr -> (this._ind(i) + nmlist + ' := ' + expr + ';\n'), 'top=' :i = tr(i):nmlist tr(i):expr -> (this._ind(i) + nmlist + ' = ' + expr + ';\n'), 'topTupl:=' :i = tr(i):nmlist tr(i):expr -> (this._ind(i) + '(' + nmlist + ') := ' + expr + ';\n'), declCon :i = tr(i):nmlist tr(i):expr -> (this._ind(i) + nmlist + ' : con ' + expr + ';\n'), declImport :i = tr(i):nmlist tr(i):nm -> (this._ind(i) + nmlist + ' : import ' + nm + ';\n'), declType :i = tr(i):nmlist tr(i):type -> (this._ind(i) + nmlist + ' : type ' + type + ';\n'), declVal :i = tr(i):nmlist tr(i):type tr(i):expr -> (this._ind(i) + nmlist + ' : ' + type + ' = ' + expr + ';\n'), declSimple :i = tr(i):nmlist tr(i):type -> (this._ind(i) + nmlist + ' : ' + type + ';\n'), include :i = tr(i):filename -> (this._ind(i) + 'include ' + filename + ';\n'), typeArrayOf :i = tr(i):type -> ('array of ' + type), typeListOf :i = tr(i):type -> ('list of ' + type), typeChanOf :i = tr(i):type -> ('chan of ' + type), typeRef :i = tr(i):type -> ('ref ' + type), typeTuple :i = tr(i):typelist -> ('(' + typelist + ')'), typelist :i = tr(i)*:types -> types.join(', '), typeMod :i = tr(i):type -> type, typeModQual :i = tr(i):mod tr(i):type -> (mod + '->' + type), typename :i = tr(i):nm -> nm, typeFn :i = tr(i):argret -> ('fn' + argret), argRet :i = tr(i):args tr(i):rettype -> ('(' + args + ') : ' + rettype), args :i = tr(i):args -> ('(' + args + ')'), argList :i = tr(i)*:xs -> xs.join(', '), nilOrDlist :i = tr(i)*:xs -> xs.join(', '), argSelfRef :i = tr(i):x tr(i):id -> (x + ' : self ref ' + id), argSelf :i = tr(i):x tr(i):id -> (x + ' : self ' + id), arg :i = tr(i):x tr(i):type -> (x + ' : ' + type), 'arg*' :i -> '*', modDecl :i = tr(i):nm tr(i):members -> ('\n' + this._ind(i) + nm + ' : module\n' + this._ind(i) + '{\n' + members + this._ind(i) + '}\n'), modMemList :i = tr(i)*:xs -> xs.join(''), modMemFn :i = tr(i):names tr(i):fntype -> (this._ind(i) + names + ' : ' + fntype + ';\n'), modMemType :i = tr(i):names tr(i):type -> (this._ind(i) + names + ' : type ' + type + ';\n'), modMemSmpl :i = tr(i):names tr(i):type -> (this._ind(i) + names + ' : ' + type + ';\n'), adtDecl :i = tr(i):nm tr(i):members -> ('\n' + this._ind(i) + nm + ' : adt\n' + this._ind(i) + '{\n' + members + this._ind(i) + '}\n'), adtMemList :i = tr(i)*:xs -> xs.join(''), adtMemFn :i = tr(i):names tr(i):fntype -> (this._ind(i) + names + ' : ' + fntype + ';\n'), adtMemSmpl :i = tr(i):names tr(i):cyclic tr(i):type -> (this._ind(i) + names + ' : ' + cyclic + type + ';\n'), cyclic :i -> 'cyclic ', fnDefn :i = tr(i):nm tr(i):argret tr(i):stmts -> ('\n' + this._ind(i) + nm + argret + '\n' + this._ind(i) + '{\n' + stmts + this._ind(i) + '}\n'), block :i = tr(i):stmts -> (this._ind(i) + '{\n' + stmts + this._ind(i) + '}\n'), ifThenElse :i = tr(i):c tr(i):t tr(i):f -> (this._ind(i) + 'if (' + c + ')\n' + t + this._ind(i) + 'else\n' + f), ifThen :i = tr(i):c tr(i):t -> (this._ind(i) + 'if (' + c + ')\n' + t), while :i = tr(i):lbl tr(i):c tr(i):stmt -> (this._ind(i) + lbl + 'while (' + c + ')\n' + stmt), doWhile :i = tr(i):lbl tr(i):stmt tr(i):c -> (this._ind(i) + lbl + 'do\n' + stmt + 'while (' + c + ');\n'), for :i = tr(i):lbl tr(i):x tr(i):c tr(i):y tr(i):z -> (this._ind(i) + lbl + 'for (' + x + '; ' + c + '; ' + y + ')\n' + z), case :i = tr(i):lbl tr(i):x tr(i):ys -> (this._ind(i) + lbl + 'case ' + x + '\n' + this._ind(i) + '{\n' + ys + this._ind(i) + '}\n'), alt :i = tr(i):lbl tr(i):ys -> (this._ind(i) + lbl + 'alt\n' + this._ind(i) + '{\n' + ys + this._ind(i) + '}\n'), break :i = tr(i):id -> (this._ind(i) + 'break ' + id + ';\n'), continue :i = tr(i):expr -> (this._ind(i) + 'continue ' + expr + ';\n'), return :i = tr(i):expr -> (this._ind(i) + 'return ' + expr + ';\n'), spawn :i = tr(i):fnCall -> (this._ind(i) + 'spawn ' + fnCall + ';\n'), exit :i -> (this._ind(i) + 'exit;\n'), stmt :i = tr(i):expr -> (this._ind(i) + expr + ';\n'), emptyStmt :i -> (this._ind(i) + ';\n'), label :i = tr(i):id -> (id + ': '), qualSSList :i = tr(i):xs tr(i):y -> (xs + y + ' =>\n'), qualSSStmt :i = tr(i):xs tr(i):y -> (xs + y), qualSimple :i = tr(i):x -> (this._ind(i) + x + ' =>\n'), qualOr :i = tr(i)*:xs -> xs.join(' or '), qualTo :i = tr(i):x tr(i):y -> (x + ' to ' + y), empty :i -> '', binOp :i = :op tr(i):x tr(i):y -> ('(' + x + ' ' + op + ' ' + y + ')'), set :i = :op tr(i):x tr(i):y -> ('(' + x + ' ' + op + ' ' + y + ')'), lvalue :i = tr(i):x -> x, lvalueTuple :i = tr(i)*:xs -> ('(' + xs.join(', ') + ')'), lvalueStar :i = tr(i):x -> ('* ' + x), monOp :i = :op tr(i):x -> ('(' + op + ' ' + x + ')'), array :i = tr(i):size tr(i):t -> ('array [' + size + '] of ' + t), arrayInit :i = tr(i):size tr(i):initlist -> ('array [' + size + '] of {' + initlist + '}'), list :i = tr(i):exprlist -> ('list of {' + exprlist + '}'), chan :i = tr(i):t -> ('chan of ' + t), cast :i = tr(i):t tr(i):x -> ('(' + t + ' ' + x + ')'), '()' :i = tr(i):exprlist -> ('(' + exprlist + ')'), dot :i = tr(i):x tr(i):y -> (x + '.' + y), '->' :i = tr(i):x tr(i):y -> (x + '->' + y), fnCall :i = tr(i):fn tr(i)*:args -> (fn + '(' + args.join(', ') + ')'), index :i = tr(i):x tr(i):j -> (x + '[' + j + ']'), slice :i = tr(i):x tr(i):a tr(i):b -> (x + '[' + a + ':' + b + ']'), sliceBegin :i = tr(i):x tr(i):a -> (x + '[' + a + ':' + ']'), incr :i = tr(i):term -> (term + '++'), decr :i = tr(i):term -> (term + '--'), exprList :i = tr(i)*:exprs -> exprs.join(', '), stmtList :i = tr(i)*:stmts -> stmts.join(''), initList :i = tr(i)*:xs -> xs.join(', '), '=>' :i = tr(i):x tr(i):y -> (x + ' => ' + y), '*=>' :i = tr(i):y -> ('* => ' + y), send :i = tr(i):l tr(i):r -> (l + ' <- = ' + r), ':=' :i = tr(i):l tr(i):r -> (l + ' := ' + r) } LimboTranslator._ind = function(i) { var indent = ''; for (j = 0; j < i; j++) indent = indent + ' '; return indent } ometa LimboLilScriptTranslator <: LimboTranslator { nmList :i = tr(i)*:xs -> xs, modMemSmpl :i = tr(i):names tr(i):type -> (this._ind(i) + names.join(', ') + ' : ' + type + ';\n'), adtMemSmpl :i = tr(i):names tr(i):cyclic tr(i):type -> (this._ind(i) + names.join(', ') + ' : ' + cyclic + type + ';\n'), lsProtoDecl :i = tr(i):nm tr(i):data tr(i):mems -> ('\n' + this._ind(i) + nm + '__proto : module\n' + this._ind(i) + '{\n' + this._ind(i + 2) + nm + ' : adt\n' + this._ind(i + 2) + '{\n' + data + this._ind(i + 2) + '}\n' + this._ind(i + 2) + nm + '__vt : ref Jbn->Object;\n' + mems + this._ind(i + 2) + 'init(jbnref : Jbn);\n' + this._ind(i) + '}\n'), lsProtoAdtDecl :i = tr(i):data -> data, lsProtoMemList :i = tr(i)*:members -> members.join(''), lsProtoMemProp :i = tr(i):names -> names.map(function(nm) { var indent = LimboTranslator._ind(i); return indent + 'get_' + nm + ', set_' + nm + ' : Jbn->method_t;\n' + indent + 'get_' + nm + '_, set_' + nm + '_ : Jbn->symbol_t;\n' }).join(''), ls :i = tr(i)*:exprs -> ('(' + exprs.join(', ') + ')'), lsExpr :i = tr(i):x tr(i)*:sels -> (x + '.__(' + sels[0].msg + '_, ' + sels[0].arg + ')'), lsSel :i = tr(i):phrase tr(i):arg -> {'msg' : phrase, 'arg' : arg}, lsPhrase :i = tr(i)*:words -> words.join(''), lsBacktickObj :i = tr(i):x -> (x + 'VT'), lsAtObj :i = tr(i):x -> x, lsObj :i = tr(i):x -> x } input = """ implement person; @prototype Person { age : int; } @property name, address; @property age; @end prototype """ tree = LimboLilScriptParser.matchAll(input, "program") [program, [nm, person], [topDeclSeq, [lsProtoDecl, [nm, Person], [lsProtoAdtDecl, [adtMemList, [adtMemSmpl, [nmList, [nm, age]], [empty], [type, int]]]], [lsProtoMemList, [lsProtoMemProp, [nmList, [nm, name], [nm, address]]], [lsProtoMemProp, [nmList, [nm, age]]]]]]] LimboLilScriptTranslator.match(tree, "toplevelTr") implement person; Person__proto : module { Person : adt { age : int; } Person__vt : ref Jbn->Object; get_name, set_name : Jbn->method_t; get_name_, set_name_ : Jbn->symbol_t; get_address, set_address : Jbn->method_t; get_address_, set_address_ : Jbn->symbol_t; get_age, set_age : Jbn->method_t; get_age_, set_age_ : Jbn->symbol_t; init(jbnref : Jbn); }