1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843 |
- "use strict";
- var Cast = require("cast.js");
- var Code = require("code.js");
- var Errors = require("errors.js");
- var Lexer = require("lexer.js");
- var Module = require("module.js");
- var op = require("operator.js");
- var Parser = require("parser.js");
- var Procedure = require("procedure.js");
- var Class = require("rtl.js").Class;
- var Scope = require("scope.js");
- var Symbol = require("symbol.js");
- var Type = require("type.js");
- var basicTypes = Type.basic;
- function getSymbolAndScope(context, id){
- var s = context.findSymbol(id);
- if (!s)
- throw new Errors.Error(
- context instanceof Type.Module
- ? "identifier '" + id + "' is not exported by module '" + context.name() + "'"
- : "undeclared identifier: '" + id + "'");
- return s;
- }
- function getSymbol(context, id){
- return getSymbolAndScope(context, id).symbol();
- }
- function unwrapTypeId(type){
- if (!(type instanceof Type.TypeId))
- throw new Errors.Error("type name expected");
- return type;
- }
- function unwrapType(type){
- return unwrapTypeId(type).type();
- }
- function getTypeSymbol(context, id){
- return unwrapType(getSymbol(context, id).info());
- }
- function throwTypeMismatch(from, to){
- throw new Errors.Error("type mismatch: expected '" + to.description() +
- "', got '" + from.description() + "'");
- }
- function checkTypeMatch(from, to){
- if (!Cast.areTypesMatch(from, to))
- throwTypeMismatch(from, to);
- }
- function checkImplicitCast(from, to){
- var result = Cast.implicit(from, to);
- if (!result)
- throwTypeMismatch(from, to);
- return result;
- }
- function promoteTypeInExpression(e, type){
- var fromType = e.type();
- if (type == Type.basic.ch && fromType instanceof Type.String){
- var v = fromType.asChar();
- if (v !== undefined)
- return new Code.Expression(v, type);
- }
- return e;
- }
- function promoteExpressionType(context, left, right){
- var rightType = right.type();
- if (!left)
- return right;
- var leftType = left.type();
- if (rightType === undefined)
- return right;
-
- return checkImplicitCast(rightType, leftType)(context, right);
- }
- function checkTypeCast(from, to, msg){
- if (from instanceof Type.Pointer)
- from = from.baseType();
- if (to instanceof Type.Pointer)
- to = to.baseType();
- var t = to.baseType();
- while (t && t != from)
- t = t.baseType();
- if (!t)
- throw new Errors.Error(msg + ": '" + to.description()
- + "' is not an extension of '" + from.description() + "'");
- }
- var ChainedContext = Class.extend({
- init: function ChainedContext(parent){this.__parent = parent;},
- parent: function(){return this.__parent;},
- codeGenerator: function(){return this.__parent.codeGenerator();},
- findSymbol: function(id){return this.__parent.findSymbol(id);},
- currentScope: function(s){return this.__parent.currentScope();},
- pushScope: function(scope){this.__parent.pushScope(scope);},
- popScope: function(){this.__parent.popScope();},
- setType: function(type){this.__parent.setType(type);},
- setDesignator: function(d){this.__parent.setDesignator(d);},
- handleExpression: function(e){this.__parent.handleExpression(e);},
- handleLiteral: function(s){this.__parent.handleLiteral(s);},
- handleConst: function(type, value, code){this.__parent.handleConst(type, value, code);},
- genTypeName: function(){return this.__parent.genTypeName();},
- genVarName: function(id){return this.__parent.genVarName(id);},
- qualifyScope: function(scope){return this.__parent.qualifyScope(scope);},
- rtl: function(){return this.__parent.rtl();}
- });
- exports.Integer = ChainedContext.extend({
- init: function IntegerContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__result = "";
- this.__isHex = false;
- },
- isLexem: function(){return true;},
- handleChar: function(c){this.__result += c;},
- handleLiteral: function(){this.__isHex = true;},
- toInt: function(s){return parseInt(this.__result, 10);},
- endParse: function(){
- var n = this.toInt();
- this.parent().handleConst(basicTypes.integer, n, n.toString());
- }
- });
- exports.HexInteger = exports.Integer.extend({
- init: function HexIntegerContext(context){
- exports.Integer.prototype.init.call(this, context);
- },
- toInt: function(s){return parseInt(this.__result, 16);}
- });
- exports.Real = ChainedContext.extend({
- init: function RealContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__result = "";
- },
- isLexem: function(){return true;},
- handleChar: function(c){this.__result += c;},
- handleLiteral: function(s){
- if (s == "D") // LONGREAL
- s = "E";
- this.__result += s;
- },
- endParse: function(){
- var n = Number(this.__result);
- this.parent().handleConst(basicTypes.real, n, n.toString());
- }
- });
- function escapeString(s){
- var result = "\"";
- for(var i = 0; i < s.length; ++i){
- var c = s[i];
- if (c == '"')
- result += "\\\"";
- else
- result += s[i];
- }
- return result + "\"";
- }
- exports.String = ChainedContext.extend({
- init: function StringContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__result = undefined;
- },
- handleString: function(s){this.__result = s;},
- toStr: function(s){return s;},
- endParse: function(){
- var s = this.toStr(this.__result);
- this.parent().handleConst(new Type.String(s), s, escapeString(s));
- }
- });
- exports.Char = exports.String.extend({
- init: function CharContext(context){
- exports.String.prototype.init.call(this, context);
- this.__result = "";
- },
- handleChar: function(c){this.__result += c;},
- toStr: function(s){return String.fromCharCode(parseInt(s, 16));}
- });
- exports.BaseType = ChainedContext.extend({
- init: function BaseTypeContext(context){
- ChainedContext.prototype.init.call(this, context);
- },
- handleSymbol: function(s){
- this.parent().setBaseType(unwrapType(s.symbol().info()));
- }
- });
- var DesignatorInfo = Class.extend({
- init: function(code, refCode, type, info, scope){
- this.__code = code;
- this.__refCode = refCode;
- this.__type = type;
- this.__info = info;
- this.__scope = scope;
- },
- code: function(){return this.__code;},
- refCode: function(){return this.__refCode(this.__code);},
- type: function(){return this.__type;},
- info: function(){return this.__info;},
- scope: function(){return this.__scope;}
- });
- exports.QualifiedIdentificator = ChainedContext.extend({
- init: function QualifiedIdentificator(context){
- ChainedContext.prototype.init.call(this, context);
- this.__module = undefined;
- this.__id = undefined;
- this.__code = "";
- },
- setIdent: function(id){
- this.__id = id;
- },
- handleLiteral: function(){
- var s = getSymbol(this, this.__id);
- if (!s.isModule())
- return false; // stop parsing
- this.__module = s.info();
- this.__code = this.__id + ".";
- return undefined;
- },
- endParse: function(){
- var s = getSymbolAndScope(this.__module ? this.__module : this, this.__id);
- var code = this.__code + this.__id;
- if (this.__module && s.symbol().isVariable())
- code += "()";
- this.parent().handleSymbol(s, code);
- }
- });
- var Identdef = Class.extend({
- init: function Identdef(id, exported){
- this.__id = id;
- this.__exported = exported;
- },
- id: function(){return this.__id;},
- exported: function(){return this.__exported;}
- });
- exports.Identdef = ChainedContext.extend({
- init: function IdentdefContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__id = undefined;
- this.__export = false;
- },
- setIdent: function(id){this.__id = id;},
- handleLiteral: function(){this.__export = true;},
- endParse: function(){
- this.parent().handleIdentef(new Identdef(this.__id, this.__export));
- }
- });
- exports.Designator = ChainedContext.extend({
- init: function Context$Designator(context){
- ChainedContext.prototype.init.call(this, context);
- this.__currentType = undefined;
- this.__info = undefined;
- this.__scope = undefined;
- this.__code = new Code.SimpleGenerator();
- this.__indexExpression = undefined;
- this.__derefCode = undefined;
- this.__propCode = undefined;
- },
- handleSymbol: function(found, code){
- this.__scope = found.scope();
- var s = found.symbol();
- var info = s.info();
- if (info instanceof Type.Type || s.isType() || s.isProcedure())
- this.__currentType = info;
- else if (s.isVariable() || s.isConst())
- this.__currentType = info.type();
- this.__info = info;
- this.__code.write(code);
- },
- setIdent: function(id){
- var t = this.__currentType;
- var isReadOnly = this.__info instanceof Type.Variable
- && this.__info.isReadOnly();
- if (t instanceof Type.Pointer){
- this.__handleDeref();
- isReadOnly = false;
- }
- else if (!(t instanceof Type.Record
- || t instanceof Type.Module
- || t instanceof Module.AnyType))
- throw new Errors.Error("cannot designate '" + t.description() + "'");
- this.__denote(id);
- this.__info = new Type.Variable(this.__currentType, isReadOnly);
- this.__scope = undefined;
- },
- codeGenerator: function(){return this.__code;},
- handleExpression: function(e){this.__indexExpression = e;},
- __handleIndexExpression: function(){
- var e = this.__indexExpression;
- var expType = e.type();
- if (expType != basicTypes.integer)
- throw new Errors.Error("'INTEGER' expression expected, got '" + expType.description() + "'");
- var type = this.__currentType;
- if (!(type instanceof Type.Array))
- throw new Errors.Error("ARRAY expected, got '" + type.description() + "'");
- var value = e.constValue();
- if (value !== undefined && value >= type.length())
- throw new Errors.Error("index out of bounds: maximum possible index is "
- + (type.length() - 1)
- + ", got " + value );
- this.__currentType = type.elementsType();
- this.__info = new Type.Variable(this.__currentType, this.__info.isReadOnly());
- },
- handleLiteral: function(s){
- if (s == "]" || s == ","){
- this.__handleIndexExpression();
- var indexCode = this.__indexExpression.deref().code();
- this.__propCode = indexCode;
- this.__code = new Code.SimpleGenerator(this.__derefCode + "[" + indexCode + "]");
- }
- if (s == "[" || s == ","){
- this.__derefCode = this.__code.result();
- this.__code = new Code.SimpleGenerator();
- }
- else if (s == "^"){
- this.__handleDeref();
- this.__info = new Type.VariableRef(this.__currentType);
- }
- },
- __handleDeref: function(){
- if (!(this.__currentType instanceof Type.Pointer))
- throw new Errors.Error("POINTER TO type expected, got '"
- + this.__currentType.description() + "'");
- this.__currentType = this.__currentType.baseType();
- if (this.__currentType instanceof Type.NonExportedRecord)
- throw new Errors.Error("POINTER TO non-exported RECORD type cannot be dereferenced");
- },
- handleTypeCast: function(type){
- if (this.__currentType instanceof Type.Record){
- if (!(this.__info instanceof Type.VariableRef))
- throw new Errors.Error(
- "invalid type cast: a value variable and cannot be used in typeguard");
- if (!(type instanceof Type.Record))
- throw new Errors.Error(
- "invalid type cast: RECORD type expected as an argument of RECORD type guard, got '"
- + type.description() + "'");
- }
- else if (this.__currentType instanceof Type.Pointer)
- if (!(type instanceof Type.Pointer))
- throw new Errors.Error(
- "invalid type cast: POINTER type expected as an argument of POINTER type guard, got '"
- + type.description() + "'");
- checkTypeCast(this.__currentType, type, "invalid type cast");
- var baseType = type instanceof Type.Pointer ? type.baseType() : type;
- var castName = this.qualifyScope(baseType.scope()) + baseType.cons();
- var code = this.rtl().typeGuard(this.__code.result(), castName);
- this.__code = new Code.SimpleGenerator(code);
- this.__currentType = type;
- },
- __denote: function(id){
- var t = this.__currentType;
- var fieldType = t.findSymbol(id);
- if (!fieldType)
- throw new Errors.Error("Type '" + t.name() + "' has no '" + id + "' field");
- this.__derefCode = this.__code.result();
- this.__propCode = "\"" + id + "\"";
- this.__code.write("." + id);
- this.__currentType = fieldType;
- },
- endParse: function(){
- var code = this.__code.result();
- var self = this;
- var refCode = function(code){return self.__makeRefCode(code);};
- this.parent().setDesignator(
- new DesignatorInfo(code, refCode, this.__currentType, this.__info, this.__scope));
- },
- __makeRefCode: function(code){
- if ((this.__currentType instanceof Type.Array)
- || (this.__currentType instanceof Type.Record)
- || (this.__info instanceof Type.VariableRef))
- return code;
- if (this.__derefCode)
- return this.rtl().makeRef(this.__derefCode, this.__propCode);
- return "{set: function($v){" + code + " = $v;}, get: function(){return " + code + ";}}";
- }
- });
- exports.Type = ChainedContext.extend({
- init: function Context$Type(context){
- ChainedContext.prototype.init.call(this, context);
- },
- handleSymbol: function(s){
- this.parent().handleSymbol(s);
- }
- });
- var HandleSymbolAsType = ChainedContext.extend({
- init: function Context$HandleSymbolAsType(context){
- ChainedContext.prototype.init.call(this, context);
- },
- handleSymbol: function(s){
- this.setType(unwrapType(s.symbol().info()));
- }
- });
- exports.FormalType = HandleSymbolAsType.extend({
- init: function FormalType(context){
- HandleSymbolAsType.prototype.init.call(this, context);
- this.__arrayDimension = 0;
- },
- setType: function(type){
- for(var i = 0; i < this.__arrayDimension; ++i)
- type = new Type.Array("ARRAY OF " + type.name()
- , undefined
- , type);
- this.parent().setType(type);
- },
- handleLiteral: function(s){
- if (s == "ARRAY")
- ++this.__arrayDimension;
- }
- });
- var ProcArg = Class.extend({
- init: function(type, isVar){
- this.type = type;
- this.isVar = isVar;
- },
- description: function(){
- return (this.isVar ? "VAR " : "") + this.type.description();
- }
- });
- exports.FormalParameters = ChainedContext.extend({
- init: function FormalParametersContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__arguments = [];
- this.__result = undefined;
- var parent = this.parent();
- this.__type = new Procedure.Type(parent.typeName());
- parent.setType(this.__type);
- },
- addArgument: function(name, arg){
- this.__arguments.push(arg);
- },
- handleSymbol: function(s){
- var resultType = unwrapType(s.symbol().info());
- if (resultType instanceof Type.Array)
- throw new Errors.Error("the result type of a procedure cannot be an ARRAY");
- if (resultType instanceof Type.Record)
- throw new Errors.Error("the result type of a procedure cannot be a RECORD");
- this.__result = resultType;
- },
- endParse: function(){
- this.__type.define(this.__arguments, this.__result);
- }
- });
- exports.FormalParametersProcDecl = exports.FormalParameters.extend({
- init: function FormalParametersProcDeclContext(context){
- exports.FormalParameters.prototype.init.call(this, context);
- },
- addArgument: function(name, arg){
- exports.FormalParameters.prototype.addArgument.call(this, name, arg);
- this.parent().addArgument(name, arg);
- },
- endParse: function(){
- exports.FormalParameters.prototype.endParse.call(this);
- this.parent().endParameters();
- }
- });
- exports.ProcDecl = ChainedContext.extend({
- init: function ProcDeclContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__id = undefined;
- this.__firstArgument = true;
- this.__type = undefined;
- this.__returnParsed = false;
- this.__outerScope = this.parent().currentScope();
- },
- handleIdentef: function(id){
- this.__id = id;
- this.codeGenerator().write("\nfunction " + id.id() + "(");
- this.parent().pushScope(new Scope.Procedure());
- },
- setIdent: function(id){
- if (this.__id.id() != id)
- throw new Errors.Error("mismatched procedure names: '" + this.__id.id()
- + "' at the begining and '" + id + "' at the end");
- this.codeGenerator().closeScope();
- this.parent().popScope();
- },
- typeName: function(){return undefined;},
- setType: function(type){
- var procSymbol = new Symbol.Symbol(this.__id.id(), type);
- this.__outerScope.addSymbol(procSymbol, this.__id.exported());
- this.__type = type;
- },
- addArgument: function(name, arg){
- if (name == this.__id.id())
- throw new Errors.Error("argument '" + name + "' has the same name as procedure");
- var readOnly = !arg.isVar && (arg.type instanceof Type.Array);
- var v = arg.isVar ? new Type.VariableRef(arg.type)
- : new Type.Variable(arg.type, readOnly);
- var s = new Symbol.Symbol(name, v);
- this.currentScope().addSymbol(s);
- var code = this.codeGenerator();
- if (!this.__firstArgument)
- code.write(", ");
- else
- this.__firstArgument = false;
- code.write(name + "/*" + arg.description() + "*/");
- },
- endParameters: function(){
- var code = this.codeGenerator();
- code.write(")");
- code.openScope();
- },
- handleReturn: function(type){
- var result = this.__type.result();
- if (!result)
- throw new Errors.Error("unexpected RETURN in PROCEDURE declared with no result type");
- if (!Cast.implicit(type, result))
- throw new Errors.Error(
- "RETURN '" + result.description() + "' expected, got '"
- + type.description() + "'");
- this.__returnParsed = true;
- },
- endParse: function(){
- var result = this.__type.result();
- if (result && !this.__returnParsed)
- throw new Errors.Error("RETURN expected at the end of PROCEDURE declared with '"
- + result.name() + "' result type");
- }
- });
- exports.Return = ChainedContext.extend({
- init: function ReturnContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__type = undefined;
- this.__code = new Code.SimpleGenerator();
- },
- codeGenerator: function(){return this.__code;},
- handleExpression: function(e){
- this.__type = e.type();
- var designator = e.designator();
- if (designator)
- writeDerefDesignatorCode(designator, this.__code);
- },
- endParse: function(){
- var parent = this.parent();
- parent.codeGenerator().write("return " + this.__code.result() + ";\n");
- parent.handleReturn(this.__type);
- }
- });
- exports.ProcParams = HandleSymbolAsType.extend({
- init: function Context$ProcParams(context){
- HandleSymbolAsType.prototype.init.call(this, context);
- this.__isVar = false;
- this.__argNamesForType = [];
- },
- handleLiteral: function(s){
- if (s == "VAR")
- this.__isVar = true;
- },
- setIdent: function(id){ this.__argNamesForType.push(id);},
- setType: function(type){
- var names = this.__argNamesForType;
- for(var i = 0; i < names.length; ++i){
- var name = names[i];
- this.parent().addArgument(name, new Procedure.Arg(type, this.__isVar));
- }
- this.__isVar = false;
- this.__argNamesForType = [];
- }
- });
- exports.PointerDecl = ChainedContext.extend({
- init: function Context$PointerDecl(context){
- ChainedContext.prototype.init.call(this, context);
- },
- handleSymbol: function(s){
- var typeId = unwrapTypeId(s.symbol().info());
- this.__setTypeId(typeId);
- },
- __setTypeId: function(typeId){
- if (!(typeId instanceof Type.ForwardTypeId)){
- var type = typeId.type();
- if (!(type instanceof Type.Record))
- throw new Errors.Error(
- "RECORD is expected as a POINTER base type, got '" + type.description() + "'");
- }
- var parent = this.parent();
- var name = parent.isAnonymousDeclaration()
- ? undefined
- : parent.genTypeName();
- var pointerType = new Type.Pointer(name, typeId);
- parent.setType(pointerType);
- },
- setType: function(type){
- var typeId = new Type.TypeId(type);
- this.currentScope().addType(typeId);
- this.__setTypeId(typeId);
- },
- findSymbol: function(id){
- var parent = this.parent();
- var existing = parent.findSymbol(id);
- if (existing)
- return existing;
- var scope = this.currentScope();
- scope.addUnresolved(id);
- var resolve = function(){return getSymbol(parent, id).info().type();};
- return new Symbol.Found(
- new Symbol.Symbol(id, new Type.ForwardTypeId(resolve)),
- scope
- );
- },
- isAnonymousDeclaration: function(){return true;},
- exportField: function(field){
- throw new Errors.Error( "cannot export anonymous RECORD field: '" + field + "'");
- }
- });
- exports.ArrayDecl = HandleSymbolAsType.extend({
- init: function Context$ArrayDecl(context){
- HandleSymbolAsType.prototype.init.call(this, context);
- this.__dimensions = undefined;
- },
- handleDimensions: function(dimensions){this.__dimensions = dimensions;},
- setType: function(type){
- var initializer = type instanceof Type.Array || type instanceof Type.Record
- ? "function(){return " + type.initializer(this) + ";}"
- : type.initializer(this);
- var dimensions = "";
- for(var i = this.__dimensions.length; i-- ;){
- var length = this.__dimensions[i];
- dimensions = length + (dimensions.length ? ", " + dimensions : "");
- var arrayInit = !i
- ? this.rtl().makeArray(dimensions + ", " + initializer)
- : undefined;
- type = new Type.Array("ARRAY OF " + type.name()
- , arrayInit
- , type
- , length);
- }
- this.__type = type;
- },
- isAnonymousDeclaration: function(){return true;},
- endParse: function(){this.parent().setType(this.__type);}
- });
- exports.ArrayDimensions = ChainedContext.extend({
- init: function ArrayDimensionsContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__dimensions = [];
- },
- codeGenerator: function(){return Code.nullGenerator;},
- handleExpression: function(e){
- var type = e.type();
- if (type !== basicTypes.integer)
- throw new Errors.Error("'INTEGER' constant expression expected, got '" + type.description() + "'");
- var value = e.constValue();
- if (value === undefined)
- throw new Errors.Error("constant expression expected as ARRAY size");
- if (value <= 0)
- throw new Errors.Error("array size must be greater than 0, got " + value);
- this.__dimensions.push(value);
- },
- endParse: function(){
- this.parent().handleDimensions(this.__dimensions);
- }
- });
- var numericOpTypeCheck = {
- expect: "numeric type",
- check: function(t){return Type.numeric.indexOf(t) != -1;}
- };
- var intOpTypeCheck = {
- expect: "INTEGER",
- check: function(t){return t == basicTypes.integer;}
- };
- var orderOpTypeCheck = {
- expect: "numeric type or CHAR or character array",
- check: function(t){
- return [basicTypes.integer, basicTypes.real, basicTypes.ch].indexOf(t) != -1
- || (t instanceof Type.Array && t.elementsType() == basicTypes.ch);
- }
- };
- var equalOpTypeCheck = {
- expect: "numeric type or SET or BOOLEAN OR CHAR or character array or POINTER or PROCEDURE",
- check: function(t){
- return [basicTypes.integer, basicTypes.real, basicTypes.set, basicTypes.bool, basicTypes.ch].indexOf(t) != -1
- || (t instanceof Type.Array && t.elementsType() == basicTypes.ch)
- || t instanceof Type.Pointer
- || t instanceof Type.Procedure
- || t == Type.nil;
- }
- };
- function assertOpType(type, check, literal){
- if (!check.check(type))
- throw new Errors.Error(
- "operator '" + literal +
- "' type mismatch: " + check.expect + " expected, got '" +
- type.description() + "'");
- }
- function assertNumericOp(type, literal, op, intOp){
- assertOpType(type, numericOpTypeCheck, literal);
- return (intOp && type == basicTypes.integer)
- ? intOp : op;
- }
- function assertIntOp(type, literal, op){
- assertOpType(type, intOpTypeCheck, literal);
- return op;
- }
- function useTypeInRelation(leftType, rightType){
- if (leftType instanceof Type.Pointer && rightType instanceof Type.Pointer){
- var type = Cast.findPointerBaseType(leftType, rightType);
- if (!type)
- type = Cast.findPointerBaseType(rightType, leftType);
- if (type)
- return type;
- }
- checkTypeMatch(rightType, leftType);
- return leftType;
- }
- function relationOp(leftType, rightType, literal){
- var o;
- var check;
- var type = useTypeInRelation(leftType, rightType);
- switch (literal){
- case "=":
- o = op.equal;
- check = equalOpTypeCheck;
- break;
- case "#":
- o = op.notEqual;
- check = equalOpTypeCheck;
- break;
- case "<":
- o = op.less;
- check = orderOpTypeCheck;
- break;
- case ">":
- o = op.greater;
- check = orderOpTypeCheck;
- break;
- case "<=":
- if (type == basicTypes.set)
- o = op.setInclL;
- else {
- o = op.eqLess;
- check = orderOpTypeCheck;
- }
- break;
- case ">=":
- if (type == basicTypes.set)
- o = op.setInclR;
- else {
- o = op.eqGreater;
- check = orderOpTypeCheck;
- }
- break;
- }
- if (check)
- assertOpType(type, check, literal);
- return o;
- }
- exports.AddOperator = ChainedContext.extend({
- init: function AddOperatorContext(context){
- ChainedContext.prototype.init.call(this, context);
- },
- handleLiteral: function(s){
- var parent = this.parent();
- var type = parent.type();
- var o;
- if (s == "+")
- o = (type == basicTypes.set) ? op.setUnion
- : assertNumericOp(type, s, op.add, op.addInt);
- else if (s == "-")
- o = (type == basicTypes.set) ? op.setDiff
- : assertNumericOp(type, s, op.sub, op.subInt);
- else if (s == "OR"){
- if (type != basicTypes.bool)
- throw new Errors.Error("BOOLEAN expected as operand of 'OR', got '"
- + type.description() + "'");
- o = op.or;
- }
- if (o)
- parent.handleBinaryOperator(o);
- }
- });
- exports.MulOperator = ChainedContext.extend({
- init: function MulOperatorContext(context){
- ChainedContext.prototype.init.call(this, context);
- },
- handleLiteral: function(s){
- var parent = this.parent();
- var type = parent.type();
- var o;
- if (s == "*")
- o = (type == basicTypes.set) ? op.setIntersection
- : assertNumericOp(type, s, op.mul, op.mulInt);
- else if (s == "/"){
- if (type == basicTypes.set)
- o = op.setSymmetricDiff;
- else if (type == basicTypes.integer)
- throw new Errors.Error("operator DIV expected for integer division");
- else
- o = assertNumericOp(type, s, op.div);
- }
- else if (s == "DIV")
- o = assertIntOp(type, s, op.divInt);
- else if (s == "MOD")
- o = assertIntOp(type, s, op.mod);
- else if (s == "&"){
- if (type != basicTypes.bool)
- throw new Errors.Error("BOOLEAN expected as operand of '&', got '"
- + type.description() + "'");
- o = op.and;
- }
- if (o)
- parent.handleOperator(o);
- }
- });
- function writeDerefDesignatorCode(designator, code){
- var info = designator.info();
- if (info instanceof Type.VariableRef)
- code.write(".get()");
- }
- exports.Term = ChainedContext.extend({
- init: function TermContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__operator = undefined;
- this.__expression = undefined;
- },
- type: function(){return this.__expression.type();},
- setDesignator: function(d){
- var value;
- var info = d.info();
- if (info instanceof Type.Const)
- value = info.value();
- this.handleExpression(
- new Code.Expression(d.code(), d.type(), d, value));
- },
- handleOperator: function(o){this.__operator = o;},
- handleConst: function(type, value, code){
- this.handleExpression(new Code.Expression(
- code, type, undefined, value));
- },
- handleFactor: function(e){
- var type = e.type();
- if (!type)
- throw new Errors.Error("procedure returning no result cannot be used in an expression");
- this.handleExpression(e);
- },
- endParse: function(){this.parent().handleTerm(this.__expression);},
- handleExpression: function(e){
- e = promoteExpressionType(this, this.__expression, e);
- if (this.__operator)
- e = this.__expression ? this.__operator(this.__expression, e)
- : this.__operator(e);
- this.__expression = e;
- }
- });
- exports.Factor = ChainedContext.extend({
- init: function FactorContext(context){
- ChainedContext.prototype.init.call(this, context);
- },
- type: function(){return this.parent().type();},
- handleLiteral: function(s){
- var parent = this.parent();
- if (s == "NIL")
- parent.handleConst(Type.nil, undefined, "null");
- else if (s == "TRUE")
- parent.handleConst(basicTypes.bool, true, "true");
- else if (s == "FALSE")
- parent.handleConst(basicTypes.bool, false, "false");
- else if (s == "~"){
- parent.setType(basicTypes.bool);
- parent.handleOperator(op.not);
- }
- },
- handleFactor: function(e){this.parent().handleFactor(e);}
- });
- exports.Set = ChainedContext.extend({
- init: function SetContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__value = 0;
- this.__expr = "";
- },
- handleElement: function(from, fromValue, to, toValue){
- if (fromValue !== undefined && (!to || toValue !== undefined)){
- if (to)
- for(var i = fromValue; i <= toValue; ++i)
- this.__value |= 1 << i;
- else
- this.__value |= 1 << fromValue;
- }
- else{
- if (this.__expr.length)
- this.__expr += ", ";
- if (to)
- this.__expr += "[" + from + ", " + to + "]";
- else
- this.__expr += from;
- }
- },
- endParse: function(){
- var parent = this.parent();
- if (!this.__expr.length)
- parent.handleConst(basicTypes.set, this.__value, this.__value.toString());
- else{
- var code = this.rtl().makeSet(this.__expr);
- if (this.__value)
- code += " | " + this.__value;
- var e = new Code.Expression(code, basicTypes.set);
- parent.handleFactor(e);
- }
- }
- });
- exports.SetElement = ChainedContext.extend({
- init: function SetElementContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__from = undefined;
- this.__fromValue = undefined;
- this.__to = undefined;
- this.__toValue = undefined;
- this.__expr = new Code.SimpleGenerator();
- },
- codeGenerator: function(){return this.__expr;},
- handleExpression: function(e){
- var value = e.constValue();
- if (!this.__from)
- {
- this.__from = this.__expr.result();
- this.__fromValue = value;
- this.__expr = new Code.SimpleGenerator();
- }
- else{
- this.__to = this.__expr.result();
- this.__toValue = value;
- }
- },
- endParse: function(){
- this.parent().handleElement(this.__from, this.__fromValue, this.__to, this.__toValue);
- }
- });
- function constValueCode(value){
- if (typeof value == "string")
- return escapeString(value);
- return value.toString();
- }
- exports.SimpleExpression = ChainedContext.extend({
- init: function SimpleExpressionContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__unaryOperator = undefined;
- this.__binaryOperator = undefined;
- this.__type = undefined;
- this.__exp = undefined;
- },
- handleTerm: function(e){
- var type = e.type();
- this.setType(type);
- var o;
- switch(this.__unaryOperator){
- case "-":
- o = (type == basicTypes.set) ? op.setComplement
- : assertNumericOp(type, this.__unaryOperator, op.negate);
- break;
- case "+":
- o = assertNumericOp(type, this.__unaryOperator, op.unaryPlus);
- break;
- }
- if (o){
- this.__exp = o(e);
- this.__unaryOperator = undefined;
- }
- else
- this.__exp = this.__exp ? this.__binaryOperator(this.__exp, e) : e;
- },
- handleLiteral: function(s){this.__unaryOperator = s;},
- type: function(){return this.__type;},
- setType: function(type){
- if (type === undefined || this.__type === undefined)
- this.__type = type;
- else
- checkImplicitCast(type, this.__type);
- },
- handleBinaryOperator: function(o){this.__binaryOperator = o;},
- endParse: function(){
- this.parent().handleSimpleExpression(this.__exp);
- }
- });
- exports.Expression = ChainedContext.extend({
- init: function ExpressionContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__relation = undefined;
- this.__expression = undefined;
- },
- handleSimpleExpression: function(e){
- if (!this.__expression){
- this.__expression = e;
- return;
- }
- var leftExpression = this.__expression;
- var leftType = leftExpression.type();
- var leftCode = leftExpression.code();
- var rightExpression = e;
- var rightType = rightExpression.type();
- var rightCode = rightExpression.code();
- var code;
- if (this.__relation == "IN"){
- if (leftType != basicTypes.integer)
- throw new Errors.Error("'INTEGER' expected as an element of SET, got '" + leftType.name() + "'");
- checkImplicitCast(rightType, basicTypes.set);
- code = "1 << " + leftCode + " & " + rightCode;
- }
- else if (this.__relation == "IS"){
- if (!(leftType instanceof Type.Pointer))
- throw new Errors.Error("POINTER to type expected before 'IS'");
- rightType = unwrapType(rightType);
- if (!(rightType instanceof Type.Record))
- throw new Errors.Error("RECORD type expected after 'IS'");
- checkTypeCast(leftType, rightType, "invalid type test");
- code = leftCode + " instanceof " + rightCode;
- }
- else {
- leftExpression = promoteTypeInExpression(leftExpression, rightType);
- rightExpression = promoteTypeInExpression(rightExpression, leftType);
- leftCode = leftExpression.code();
- rightCode = rightExpression.code();
- //checkImplicitCast(rightExpression.type(), leftExpression.type());
- }
- var value;
- if (!code){
- var o = relationOp(leftExpression.type(), rightExpression.type(), this.__relation);
- var oResult = o(leftExpression, rightExpression, this);
- code = oResult.code();
- value = oResult.constValue();
- }
- this.__expression = new Code.Expression(code, basicTypes.bool, undefined, value);
- },
- handleLiteral: function(relation){
- this.__relation = relation;
- },
- codeGenerator: function(){return Code.nullGenerator;},
- endParse: function(){
- var parent = this.parent();
- parent.codeGenerator().write(this.__expression.code());
- parent.handleExpression(this.__expression);
- }
- });
- function handleIfExpression(e){
- var type = e.type();
- if (type !== basicTypes.bool)
- throw new Errors.Error("'BOOLEAN' expression expected, got '" + type.description() + "'");
- }
- var IfContextBase = ChainedContext.extend({
- init: function(context){
- ChainedContext.prototype.init.call(this, context);
- },
- endParse: function(){
- var gen = this.codeGenerator();
- gen.write(")");
- gen.openScope();
- },
- handleExpression: handleIfExpression
- });
- exports.If = IfContextBase.extend({
- init: function IfContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.codeGenerator().write("if (");
- }
- });
- exports.ElseIf = IfContextBase.extend({
- init: function ElseIfContext(context){
- ChainedContext.prototype.init.call(this, context);
- var gen = this.codeGenerator();
- gen.closeScope();
- gen.write("else if (");
- }
- });
- exports.Else = ChainedContext.extend({
- init: function ElseContext(context){
- ChainedContext.prototype.init.call(this, context);
- var gen = this.codeGenerator();
- gen.closeScope();
- gen.write("else ");
- gen.openScope();
- }
- });
- exports.emitEndStatement = function(context){
- context.codeGenerator().write(";\n");
- };
- exports.emitIfEnd = function(context){
- context.codeGenerator().closeScope();
- };
- exports.Case = ChainedContext.extend({
- init: function CaseContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__type = undefined;
- this.__firstCase = true;
- this.genVarName("$c");
- this.codeGenerator().write("$c = ");
- },
- handleExpression: function(e){
- var type = e.type();
- var gen = this.codeGenerator();
- if (type instanceof Type.String){
- var v = type.asChar();
- if (v !== undefined){
- gen.write(v);
- type = basicTypes.ch;
- }
- }
- if (type != basicTypes.integer && type != basicTypes.ch)
- throw new Errors.Error("'INTEGER' or 'CHAR' expected as CASE expression");
- this.__type = type;
- gen.write(";\n");
- },
- beginCase: function(){
- if (this.__firstCase)
- this.__firstCase = false;
- else
- this.codeGenerator().write("else ");
- },
- handleLabelType: function(type){
- if (type !== this.__type)
- throw new Errors.Error(
- "label must be '" + this.__type.name() + "' (the same as case expression), got '"
- + type.name() + "'");
- }
- });
- exports.CaseLabelList = ChainedContext.extend({
- init: function CaseLabelListContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__glue = "";
- },
- handleLabelType: function(type){this.parent().handleLabelType(type);},
- handleRange: function(from, to){
- if (!this.__glue)
- this.parent().caseLabelBegin();
- var cond = to === undefined
- ? "$c === " + from
- : "($c >= " + from + " && $c <= " + to + ")";
- this.codeGenerator().write(this.__glue + cond);
- this.__glue = " || ";
- },
- endParse: function(){this.parent().caseLabelEnd();}
- });
- exports.CaseLabel = ChainedContext.extend({
- init: function CaseLabelContext(context){
- ChainedContext.prototype.init.call(this, context);
- },
- caseLabelBegin: function(){
- this.parent().beginCase();
- this.codeGenerator().write("if (");
- },
- caseLabelEnd: function(){
- var gen = this.codeGenerator();
- gen.write(")");
- gen.openScope();
- },
- handleLabelType: function(type){this.parent().handleLabelType(type);},
- handleRange: function(from, to){this.parent().handleRange(from, to);},
- endParse: function(){this.codeGenerator().closeScope();}
- });
- exports.CaseRange = ChainedContext.extend({
- init: function CaseRangeContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__from = undefined;
- this.__to = undefined;
- },
- codeGenerator: function(){return Code.nullGenerator;}, // suppress any output
- handleLabel: function(type, v){
- this.parent().handleLabelType(type);
- if (this.__from === undefined )
- this.__from = v;
- else
- this.__to = v;
- },
- handleConst: function(type, value){
- if (type instanceof Type.String){
- value = type.asChar();
- if (value === undefined)
- throw new Errors.Error("single-character string expected");
- type = basicTypes.ch;
- }
- this.handleLabel(type, value);
- },
- setIdent: function(id){
- var s = getSymbol(this.parent(), id);
- if (!s.isConst())
- throw new Errors.Error("'" + id + "' is not a constant");
-
- var type = s.info().type();
- if (type instanceof Type.String)
- this.handleConst(type, undefined);
- else
- this.handleLabel(type, s.info().value());
- },
- endParse: function(){this.parent().handleRange(this.__from, this.__to);}
- });
- exports.While = ChainedContext.extend({
- init: function WhileContext(context){
- ChainedContext.prototype.init.call(this, context);
- var gen = this.codeGenerator();
- gen.write("while (true)");
- gen.openScope();
- gen.write("if (");
- },
- handleExpression: handleIfExpression,
- endParse: function(){
- var gen = this.codeGenerator();
- gen.write(")");
- gen.openScope();
- }
- });
- exports.emitWhileEnd = function(context){
- var gen = context.codeGenerator();
- gen.closeScope(" else break;\n");
- gen.closeScope();
- };
- exports.Repeat = ChainedContext.extend({
- init: function RepeatContext(context){
- ChainedContext.prototype.init.call(this, context);
- var gen = context.codeGenerator();
- gen.write("do ");
- gen.openScope();
- }
- });
- exports.Until = ChainedContext.extend({
- init: function UntilContext(context){
- ChainedContext.prototype.init.call(this, context);
- var gen = context.codeGenerator();
- gen.closeScope(" while (");
- },
- handleExpression: handleIfExpression,
- endParse: function(){this.codeGenerator().write(");\n");}
- });
- exports.For = ChainedContext.extend({
- init: function ForContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__var = undefined;
- this.__initExprParsed = false;
- this.__toExpr = new Code.SimpleGenerator();
- this.__toParsed = false;
- this.__by_parsed = false;
- this.__by = undefined;
- },
- setIdent: function(id){
- var s = getSymbol(this.parent(), id);
- if (!s.isVariable())
- throw new Errors.Error("'" + s.id() + "' is not a variable");
- if (s.info().type() !== basicTypes.integer)
- throw new Errors.Error(
- "'" + s.id() + "' is a 'BOOLEAN' variable, 'FOR' control variable must be 'INTEGER'");
- this.codeGenerator().write("for (" + id + " = ");
- this.__var = id;
- },
- handleExpression: function(e){
- var type = e.type();
- var value = e.constValue();
- if (type !== basicTypes.integer)
- throw new Errors.Error(
- !this.__initExprParsed
- ? "'INTEGER' expression expected to assign '" + this.__var
- + "', got '" + type.description() + "'"
- : !this.__toParsed
- ? "'INTEGER' expression expected as 'TO' parameter, got '" + type.description() + "'"
- : "'INTEGER' expression expected as 'BY' parameter, got '" + type.description() + "'"
- );
- if (!this.__initExprParsed)
- this.__initExprParsed = true;
- else if (!this.__toParsed)
- this.__toParsed = true;
- else if ( value === undefined )
- throw new Errors.Error("constant expression expected as 'BY' parameter");
- else
- this.__by = value;
- },
- codeGenerator: function(){
- if (this.__initExprParsed && !this.__toParsed)
- return this.__toExpr;
- if (this.__toParsed && !this.__by_parsed)
- return Code.nullGenerator; // suppress output for BY expression
-
- return this.parent().codeGenerator();
- },
- handleBegin: function(){
- this.__by_parsed = true;
- var relation = this.__by < 0 ? " >= " : " <= ";
- var step = this.__by === undefined
- ? "++" + this.__var
- : this.__var + (this.__by < 0
- ? " -= " + -this.__by
- : " += " + this.__by);
- var s = "; " + this.__var + relation + this.__toExpr.result() + "; " + step + ")";
- var gen = this.codeGenerator();
- gen.write(s);
- gen.openScope();
- },
- endParse: function(){this.codeGenerator().closeScope();}
- });
- exports.emitForBegin = function(context){context.handleBegin();};
- exports.CheckAssignment = ChainedContext.extend({
- init: function Context$CheckAssignment(context){
- ChainedContext.prototype.init.call(this, context);
- },
- handleLiteral: function(s){
- if (s == "=")
- throw new Errors.Error("did you mean ':=' (statement expected, got expression)?");
- }
- });
- exports.Assignment = ChainedContext.extend({
- init: function AssignmentContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__left = undefined;
- },
- codeGenerator: function(){/*throw new Error("Test");*/ return Code.nullGenerator;},
- setDesignator: function(d){
- this.__left = new Code.Expression(d.code(), d.type(), d);
- },
- handleExpression: function(e){
- this.parent().codeGenerator().write(op.assign(this.__left, e, this));
- }
- });
- exports.ConstDecl = ChainedContext.extend({
- init: function ConstDeclContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__id = undefined;
- this.__type = undefined;
- this.__value = undefined;
- },
- handleIdentef: function(id){
- this.__id = id;
- this.codeGenerator().write("var " + id.id() + " = ");
- },
- handleExpression: function(e){
- var value = e.constValue();
- if (value === undefined)
- throw new Errors.Error("constant expression expected");
- this.__type = e.type();
- this.__value = value;
- },
- endParse: function(){
- var c = new Type.Const(this.__type, this.__value);
- this.currentScope().addSymbol(new Symbol.Symbol(this.__id.id(), c), this.__id.exported());
- this.codeGenerator().write(";\n");
- }
- });
- function checkIfFieldCanBeExported(name, idents, hint){
- for(var i = 0; i < idents.length; ++i){
- var id = idents[i];
- if (!id.exported())
- throw new Errors.Error(
- "field '" + name + "' can be exported only if " + hint + " '" +
- id.id() + "' itself is exported too");
- }
- }
- exports.VariableDeclaration = HandleSymbolAsType.extend({
- init: function Context$VariableDeclaration(context){
- HandleSymbolAsType.prototype.init.call(this, context);
- this.__idents = [];
- this.__type = undefined;
- },
- handleIdentef: function(id){this.__idents.push(id);},
- exportField: function(name){
- checkIfFieldCanBeExported(name, this.__idents, "variable");
- },
- setType: function(type){this.__type = type;},
- typeName: function(){return undefined;},
- isAnonymousDeclaration: function(){return true;},
- endParse: function(){
- var v = new Type.Variable(this.__type);
- var idents = this.__idents;
- var gen = this.codeGenerator();
- for(var i = 0; i < idents.length; ++i){
- var id = idents[i];
- if (id.exported()
- && (this.__type instanceof Type.Record
- || this.__type instanceof Type.Array))
- throw new Errors.Error("only scalar type variables can be exported");
- var varName = id.id();
- this.currentScope().addSymbol(new Symbol.Symbol(varName, v), id.exported());
- var t = v.type();
- gen.write("var " + varName + " = " + t.initializer(this) + ";");
- }
- gen.write("\n");
- }
- });
- exports.FieldListDeclaration = HandleSymbolAsType.extend({
- init: function Context$FieldListDeclaration(context){
- HandleSymbolAsType.prototype.init.call(this, context);
- this.__idents = [];
- this.__type = undefined;
- },
- typeName: function(){return undefined;},
- handleIdentef: function(id) {this.__idents.push(id);},
- exportField: function(name){
- checkIfFieldCanBeExported(name, this.__idents, "field");
- },
- setType: function(type) {this.__type = type;},
- isAnonymousDeclaration: function(){return true;},
- endParse: function(){
- var idents = this.__idents;
- var parent = this.parent();
- for(var i = 0; i < idents.length; ++i)
- parent.addField(idents[i], this.__type);
- }
- });
- function assertProcType(type){
- if (!(type instanceof Type.Procedure) && !(type instanceof Module.AnyType))
- throw new Errors.Error("PROCEDURE expected, got '" + type.description() + "'");
- }
- exports.ActualParameters = ChainedContext.extend({
- init: function ActualParametersContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.parent().hasActualParameters();
- }
- });
- var ProcedureCall = ChainedContext.extend({
- init: function ProcedureCallContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__type = undefined;
- this.__procCall = undefined;
- this.__code = new Code.SimpleGenerator();
- },
- setDesignator: function(d){
- var type = d.type();
- assertProcType(type);
- this.__type = type;
- this.__procCall = type.callGenerator(this, d.code());
- this.__callExpression = undefined;
- },
- codeGenerator: function(){return this.__code;},
- type: function(){return this.__type;},
- hasActualParameters: function(){},
- handleExpression: function(e){this.__procCall.handleArgument(e);},
- callExpression: function(){return this.__callExpression;},
- endParse: function(){this.__callExpression = this.__procCall.end();}
- });
- exports.StatementProcedureCall = ProcedureCall.extend({
- init: function StatementProcedureCallContext(context){
- ProcedureCall.prototype.init.call(this, context);
- },
- endParse: function(){
- ProcedureCall.prototype.endParse.call(this);
- var e = this.callExpression();
- var type = e.type();
- if (type && !(type instanceof Module.AnyType ))
- throw new Errors.Error("procedure returning a result cannot be used as a statement");
- this.parent().codeGenerator().write(e.code());
- }
- });
- exports.ExpressionProcedureCall = ProcedureCall.extend({
- init: function ExpressionProcedureCall(context){
- ProcedureCall.prototype.init.call(this, context);
- this.__designator = undefined;
- this.__hasActualParameters = false;
- },
- setDesignator: function(d){
- this.__designator = d;
- },
- hasActualParameters: function(){
- ProcedureCall.prototype.setDesignator.call(this, this.__designator);
- this.__hasActualParameters = true;
- },
- endParse: function(){
- var parent = this.parent();
- if (this.__hasActualParameters){
- ProcedureCall.prototype.endParse.call(this);
- parent.handleFactor(this.callExpression());
- }
- else{
- var d = this.__designator;
- var info = d.info();
- if (info instanceof Type.Procedure){
- if (info instanceof Procedure.Std)
- throw new Errors.Error(info.description() + " cannot be referenced");
- var scope = d.scope();
- if (scope && scope.id() == "procedure")
- throw new Errors.Error("local procedure '" + d.code() + "' cannot be referenced");
- }
- parent.setDesignator(d);
- }
- }
- });
- function isTypeRecursive(type, base){
- if (type == base)
- return true;
- if (type instanceof Type.Record){
- if (isTypeRecursive(type.baseType(), base))
- return true;
- var fields = type.ownFields();
- for(var fieldName in fields){
- if (isTypeRecursive(fields[fieldName], base))
- return true;
- }
- }
- else if (type instanceof Type.Array)
- return isTypeRecursive(type.elementsType(), base);
- return false;
- }
- exports.RecordDecl = ChainedContext.extend({
- init: function RecordDeclContext(context){
- ChainedContext.prototype.init.call(this, context);
- var parent = this.parent();
- var cons = parent.genTypeName();
- var name = parent.isAnonymousDeclaration() ? undefined : cons;
- this.__type = new Type.Record(name, cons, context.currentScope());
- parent.setType(this.__type);
- parent.codeGenerator().write("var " + cons + " = ");
- },
- addField: function(field, type){
- if (isTypeRecursive(type, this.__type))
- throw new Errors.Error("recursive field definition: '"
- + field.id() + "'");
- this.__type.addField(field, type);
- if (field.exported())
- this.parent().exportField(field.id());
- },
- setBaseType: function(type){
- if (!(type instanceof Type.Record))
- throw new Errors.Error(
- "RECORD type is expected as a base type, got '"
- + type.description()
- + "'");
- if (isTypeRecursive(type, this.__type))
- throw new Errors.Error("recursive inheritance: '"
- + this.__type.name() + "'");
- this.__type.setBaseType(type);
- },
- endParse: function(){
- var type = this.__type;
- var baseType = type.baseType();
- var gen = this.codeGenerator();
- gen.write((baseType ? baseType.name() + ".extend" : this.rtl().extendId()) + "(");
- gen.openScope();
- gen.write("init: function " + this.__type.cons() + "()");
- gen.openScope();
- if (baseType)
- gen.write(baseType.name() + ".prototype.init.call(this);\n");
- var ownFields = type.ownFields();
- for(var f in ownFields)
- gen.write("this." + f + " = " + ownFields[f].initializer(this) + ";\n");
- gen.closeScope();
- gen.closeScope(");\n");
- }
- });
- exports.TypeDeclaration = ChainedContext.extend({
- init: function TypeDeclarationContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__id = undefined;
- this.__symbol = undefined;
- },
- handleIdentef: function(id){
- var typeId = new Type.LazyTypeId();
- var symbol = this.currentScope().addType(typeId, id);
- this.__id = id;
- this.__symbol = symbol;
- },
- setType: function(type){
- this.__symbol.info().define(type);
- this.currentScope().resolve(this.__symbol);
- },
- typeName: function(){return this.__id.id();},
- genTypeName: function(){return this.__id.id();},
- isAnonymousDeclaration: function(){return false;},
- type: function(){return this.parent().type();},
- exportField: function(name){
- checkIfFieldCanBeExported(name, [this.__id], "record");
- }
- });
- exports.TypeSection = ChainedContext.extend({
- init: function TypeSection(context){
- ChainedContext.prototype.init.call(this, context);
- },
- endParse: function(){
- var unresolved = this.currentScope().unresolved();
- if (unresolved.length)
- throw new Errors.Error("no declaration found for '" + unresolved.join("', '") + "'");
- }
- });
- exports.TypeCast = ChainedContext.extend({
- init: function TypeCastContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__type = undefined;
- },
- handleSymbol: function(s){
- s = s.symbol();
- if (!s.isType())
- return; // this is not a type cast, may be procedure call
- this.__type = s.info().type();
- },
- endParse: function(){
- if (this.__type === undefined)
- return false;
- this.parent().handleTypeCast(this.__type);
- return true;
- }
- });
- exports.ModuleDeclaration = ChainedContext.extend({
- init: function ModuleDeclarationContext(context){
- ChainedContext.prototype.init.call(this, context);
- this.__name = undefined;
- this.__imports = {};
- this.__moduleScope = undefined;
- this.__moduleGen = undefined;
- },
- setIdent: function(id){
- var parent = this.parent();
- if (this.__name === undefined ) {
- this.__name = id;
- this.__moduleScope = new Scope.Module(id);
- parent.pushScope(this.__moduleScope);
- }
- else if (id === this.__name){
- var scope = parent.currentScope();
- scope.strip();
- var exports = scope.exports();
- scope.module().info().defineExports(exports);
- this.codeGenerator().write(this.__moduleGen.epilog(exports));
- }
- else
- throw new Errors.Error("original module name '" + this.__name + "' expected, got '" + id + "'" );
- },
- findModule: function(name){
- if (name == this.__name)
- throw new Errors.Error("module '" + this.__name + "' cannot import itself");
- return this.parent().findModule(name);
- },
- handleImport: function(modules){
- var scope = this.currentScope();
- var moduleAliases = {};
- for(var i = 0; i < modules.length; ++i){
- var s = modules[i];
- var name = s.info().name();
- this.__imports[name] = s;
- scope.addSymbol(s);
- moduleAliases[name] = s.id();
- }
- this.__moduleGen = this.parent().makeModuleGenerator(
- this.__name,
- moduleAliases);
- this.codeGenerator().write(this.__moduleGen.prolog());
- },
- qualifyScope: function(scope){
- if (scope != this.__moduleScope && scope instanceof Scope.Module)
- return this.__imports[scope.module().id()].id() + ".";
- return "";
- }
- });
- var ModuleImport = ChainedContext.extend({
- init: function ModuleImport(context){
- ChainedContext.prototype.init.call(this, context);
- this.__import = {};
- this.__currentModule = undefined;
- this.__currentAlias = undefined;
- },
- setIdent: function(id){
- this.__currentModule = id;
- },
- handleLiteral: function(s){
- if (s == ":=")
- this.__currentAlias = this.__currentModule;
- else if (s == ",")
- this.__handleImport();
- },
- endParse: function(){
- if (this.__currentModule)
- this.__handleImport();
- var modules = [];
- var unresolved = [];
- for(var alias in this.__import){
- var moduleName = this.__import[alias];
- var module = this.parent().findModule(moduleName);
- if (!module)
- unresolved.push(moduleName);
- else
- modules.push(new Symbol.Symbol(alias, module));
- }
- if (unresolved.length)
- throw new Errors.Error("module(s) not found: " + unresolved.join(", "));
-
- this.parent().handleImport(modules);
- },
- __handleImport: function(){
- var alias = this.__currentAlias;
- if (!alias)
- alias = this.__currentModule;
- else
- this.__currentAlias = undefined;
-
- for(var a in this.__import){
- if (a == alias)
- throw new Errors.Error("duplicated alias: '" + alias +"'");
- if (this.__import[a] == this.__currentModule)
- throw new Errors.Error("module already imported: '" + this.__currentModule +"'");
- }
- this.__import[alias] = this.__currentModule;
- }
- });
- exports.ModuleImport = ModuleImport;
- exports.Context = Class.extend({
- init: function Context(code, moduleGeneratorFactory, rtl, moduleResolver){
- this.__code = code;
- this.__moduleGeneratorFactory = moduleGeneratorFactory;
- this.__scopes = [];
- this.__gen = 0;
- this.__vars = [];
- this.__rtl = rtl;
- this.__moduleResolver = moduleResolver;
- },
- genTypeName: function(){
- ++this.__gen;
- return "anonymous$" + this.__gen;
- },
- genVarName: function(id){
- if (this.__vars.indexOf(id) === -1) {
- this.__code.write("var " + id + ";\n");
- this.__vars.push(id);
- }
- },
- findSymbol: function(ident){
- for(var i = this.__scopes.length; i--;){
- var scope = this.__scopes[i];
- var s = scope.findSymbol(ident);
- if (s)
- return new Symbol.Found(s, scope);
- }
- return undefined;
- },
- currentScope: function(){return this.__scopes[this.__scopes.length - 1];},
- pushScope: function(scope){this.__scopes.push(scope);},
- popScope: function(){this.__scopes.pop();},
- handleExpression: function(){},
- handleLiteral: function(){},
- codeGenerator: function(){return this.__code;},
- makeModuleGenerator: function(name, imports){
- return this.__moduleGeneratorFactory(name, imports);
- },
- rtl: function(){return this.__rtl;},
- findModule: function(name){
- if (name == "JS"){
- return new Module.JS();
- }
- return this.__moduleResolver ? this.__moduleResolver(name) : undefined;
- }
- });
|