|
@@ -1,1843 +0,0 @@
|
|
|
-"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;
|
|
|
- }
|
|
|
-});
|