All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xdef.impl.compile.CompileCode Maven / Gradle / Ivy

The newest version!
package org.xdef.impl.compile;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.xdef.XDBNFGrammar;
import org.xdef.XDBNFRule;
import org.xdef.XDConstants;
import org.xdef.XDContainer;
import org.xdef.XDNamedValue;
import org.xdef.XDParser;
import org.xdef.XDValue;
import static org.xdef.XDValueID.XD_ANY;
import static org.xdef.XDValueID.XD_BIGINTEGER;
import static org.xdef.XDValueID.XD_BNFGRAMMAR;
import static org.xdef.XDValueID.XD_BNFRULE;
import static org.xdef.XDValueID.XD_BOOLEAN;
import static org.xdef.XDValueID.XD_CHAR;
import static org.xdef.XDValueID.XD_CONTAINER;
import static org.xdef.XDValueID.XD_DATETIME;
import static org.xdef.XDValueID.XD_DECIMAL;
import static org.xdef.XDValueID.XD_DOUBLE;
import static org.xdef.XDValueID.XD_DURATION;
import static org.xdef.XDValueID.XD_ELEMENT;
import static org.xdef.XDValueID.XD_INPUT;
import static org.xdef.XDValueID.XD_LOCALE;
import static org.xdef.XDValueID.XD_LONG;
import static org.xdef.XDValueID.XD_NAMEDVALUE;
import static org.xdef.XDValueID.XD_NULL;
import static org.xdef.XDValueID.XD_OUTPUT;
import static org.xdef.XDValueID.XD_PARSER;
import static org.xdef.XDValueID.XD_PARSERESULT;
import static org.xdef.XDValueID.XD_REPORT;
import static org.xdef.XDValueID.XD_SERVICE;
import static org.xdef.XDValueID.XD_STATEMENT;
import static org.xdef.XDValueID.XD_STRING;
import static org.xdef.XDValueID.XD_UNDEF;
import static org.xdef.XDValueID.XD_VOID;
import static org.xdef.XDValueID.XD_XPATH;
import static org.xdef.XDValueID.X_ATTR_REF;
import static org.xdef.XDValueID.X_NOTYPE_VALUE;
import org.xdef.impl.XDebugInfo;
import org.xdef.impl.XVariableTable;
import org.xdef.impl.code.CodeExtMethod;
import org.xdef.impl.code.CodeI1;
import org.xdef.impl.code.CodeOp;
import org.xdef.impl.code.CodeParser;
import org.xdef.impl.code.CodeS1;
import org.xdef.impl.code.DefBNFGrammar;
import org.xdef.impl.code.DefBigInteger;
import org.xdef.impl.code.DefBoolean;
import org.xdef.impl.code.DefChar;
import org.xdef.impl.code.DefContainer;
import org.xdef.impl.code.DefDate;
import org.xdef.impl.code.DefDecimal;
import org.xdef.impl.code.DefDouble;
import org.xdef.impl.code.DefLocale;
import org.xdef.impl.code.DefLong;
import org.xdef.impl.code.DefNull;
import org.xdef.impl.code.DefRegex;
import org.xdef.impl.code.DefString;
import org.xdef.impl.code.DefXPathExpr;
import org.xdef.impl.code.DefXQueryExpr;
import org.xdef.impl.ext.XExtUtils;
import org.xdef.impl.parsers.XDParseCDATA;
import org.xdef.impl.parsers.XDParseFalse;
import org.xdef.impl.parsers.XDParseTrue;
import org.xdef.impl.xml.KNamespace;
import org.xdef.model.XMVariable;
import org.xdef.msg.SYS;
import org.xdef.msg.XDEF;
import org.xdef.msg.XML;
import org.xdef.proc.XDLexicon;
import org.xdef.proc.XXData;
import org.xdef.proc.XXElement;
import org.xdef.proc.XXNode;
import org.xdef.sys.Report;
import org.xdef.sys.SBuffer;
import org.xdef.sys.SPosition;
import org.xdef.sys.SRuntimeException;
import org.xdef.sys.SThrowable;
import org.xdef.sys.StringParser;
import static org.xdef.XDValueID.X_PARSEITEM;
import static org.xdef.XDValueID.X_UNIQUESET;
import static org.xdef.XDValueID.X_UNIQUESET_KEY;
import static org.xdef.XDValueID.X_UNIQUESET_M;
import static org.xdef.XDValueID.X_UNIQUESET_NAMED;
import static org.xdef.impl.code.CodeTable.ATTR_EXIST;
import static org.xdef.impl.code.CodeTable.ATTR_REF;
import static org.xdef.impl.code.CodeTable.BNFRULE_PARSE;
import static org.xdef.impl.code.CodeTable.CALL_OP;
import static org.xdef.impl.code.CodeTable.CHECK_TYPE;
import static org.xdef.impl.code.CodeTable.CMPEQ;
import static org.xdef.impl.code.CodeTable.CMPGE;
import static org.xdef.impl.code.CodeTable.CMPGT;
import static org.xdef.impl.code.CodeTable.CMPLE;
import static org.xdef.impl.code.CodeTable.CMPLT;
import static org.xdef.impl.code.CodeTable.CMPNE;
import static org.xdef.impl.code.CodeTable.COMPILE_REGEX;
import static org.xdef.impl.code.CodeTable.CONTEXT_GETTEXT;
import static org.xdef.impl.code.CodeTable.CREATE_ELEMENT;
import static org.xdef.impl.code.CodeTable.CREATE_ELEMENTS;
import static org.xdef.impl.code.CodeTable.CREATE_NAMEDVALUE;
import static org.xdef.impl.code.CodeTable.DATE_FORMAT;
import static org.xdef.impl.code.CodeTable.DEL_ATTR;
import static org.xdef.impl.code.CodeTable.EQUALS_OP;
import static org.xdef.impl.code.CodeTable.EXTMETHOD;
import static org.xdef.impl.code.CodeTable.EXTMETHOD_CHKEL_XDARRAY;
import static org.xdef.impl.code.CodeTable.EXTMETHOD_XDARRAY;
import static org.xdef.impl.code.CodeTable.EXTMETHOD_XXNODE;
import static org.xdef.impl.code.CodeTable.EXTMETHOD_XXNODE_XDARRAY;
import static org.xdef.impl.code.CodeTable.FLOAT_FORMAT;
import static org.xdef.impl.code.CodeTable.FORMAT_STRING;
import static org.xdef.impl.code.CodeTable.FROM_ELEMENT;
import static org.xdef.impl.code.CodeTable.GETATTR_FROM_CONTEXT;
import static org.xdef.impl.code.CodeTable.GETELEMS_FROM_CONTEXT;
import static org.xdef.impl.code.CodeTable.GETELEM_FROM_CONTEXT;
import static org.xdef.impl.code.CodeTable.GET_ATTR;
import static org.xdef.impl.code.CodeTable.GET_ATTR_NAME;
import static org.xdef.impl.code.CodeTable.GET_BNFRULE;
import static org.xdef.impl.code.CodeTable.GET_DBQUERY;
import static org.xdef.impl.code.CodeTable.GET_ELEMENT;
import static org.xdef.impl.code.CodeTable.GET_NS;
import static org.xdef.impl.code.CodeTable.GET_XPATH;
import static org.xdef.impl.code.CodeTable.GET_XPATH_FROM_SOURCE;
import static org.xdef.impl.code.CodeTable.GET_XQUERY;
import static org.xdef.impl.code.CodeTable.HAS_ATTR;
import static org.xdef.impl.code.CodeTable.INTEGER_FORMAT;
import static org.xdef.impl.code.CodeTable.JMPEQ;
import static org.xdef.impl.code.CodeTable.JMPF_OP;
import static org.xdef.impl.code.CodeTable.JMPGE;
import static org.xdef.impl.code.CodeTable.JMPGT;
import static org.xdef.impl.code.CodeTable.JMPLE;
import static org.xdef.impl.code.CodeTable.JMPLT;
import static org.xdef.impl.code.CodeTable.JMPNE;
import static org.xdef.impl.code.CodeTable.JMPT_OP;
import static org.xdef.impl.code.CodeTable.JMP_OP;
import static org.xdef.impl.code.CodeTable.LD_CODE;
import static org.xdef.impl.code.CodeTable.LD_CONST;
import static org.xdef.impl.code.CodeTable.LD_GLOBAL;
import static org.xdef.impl.code.CodeTable.LD_LOCAL;
import static org.xdef.impl.code.CodeTable.LD_TRUE_AND_SKIP;
import static org.xdef.impl.code.CodeTable.LD_XMODEL;
import static org.xdef.impl.code.CodeTable.NEW_BNFGRAMAR;
import static org.xdef.impl.code.CodeTable.NEW_CONTAINER;
import static org.xdef.impl.code.CodeTable.NEW_LOCALE;
import static org.xdef.impl.code.CodeTable.NEW_PARSER;
import static org.xdef.impl.code.CodeTable.NOT_B;
import static org.xdef.impl.code.CodeTable.NULL_OR_TO_STRING;
import static org.xdef.impl.code.CodeTable.OUT1_STREAM;
import static org.xdef.impl.code.CodeTable.OUTLN1_STREAM;
import static org.xdef.impl.code.CodeTable.OUTLN_STREAM;
import static org.xdef.impl.code.CodeTable.OUT_STREAM;
import static org.xdef.impl.code.CodeTable.PARSEANDCHECK;
import static org.xdef.impl.code.CodeTable.PARSERESULT_MATCH;
import static org.xdef.impl.code.CodeTable.PARSE_DATE;
import static org.xdef.impl.code.CodeTable.PARSE_FLOAT;
import static org.xdef.impl.code.CodeTable.PARSE_INT;
import static org.xdef.impl.code.CodeTable.PARSE_OP;
import static org.xdef.impl.code.CodeTable.POP_OP;
import static org.xdef.impl.code.CodeTable.PRINTF_STREAM;
import static org.xdef.impl.code.CodeTable.PUT_ERROR;
import static org.xdef.impl.code.CodeTable.PUT_ERROR1;
import static org.xdef.impl.code.CodeTable.SET_ATTR;
import static org.xdef.impl.code.CodeTable.SET_ELEMENT;
import static org.xdef.impl.code.CodeTable.SET_NAMEDVALUE;
import static org.xdef.impl.code.CodeTable.STACK_DUP;
import static org.xdef.impl.code.CodeTable.STACK_TO_CONTAINER;
import static org.xdef.impl.code.CodeTable.STOP_OP;
import static org.xdef.impl.code.CodeTable.ST_GLOBAL;
import static org.xdef.impl.code.CodeTable.ST_LOCAL;
import static org.xdef.impl.code.CodeTable.ST_XMODEL;
import static org.xdef.impl.code.CodeTable.TO_BIGINTEGER_X;
import static org.xdef.impl.code.CodeTable.TO_BOOLEAN;
import static org.xdef.impl.code.CodeTable.TO_CHAR_X;
import static org.xdef.impl.code.CodeTable.TO_DECIMAL_X;
import static org.xdef.impl.code.CodeTable.TO_FLOAT;
import static org.xdef.impl.code.CodeTable.TO_FLOAT_X;
import static org.xdef.impl.code.CodeTable.TO_INT_X;
import static org.xdef.impl.code.CodeTable.TO_MILLIS;
import static org.xdef.impl.code.CodeTable.TO_STRING;
import static org.xdef.impl.code.CodeTable.UNIQUESET_BIND;
import static org.xdef.impl.compile.CompileBase.NO_MODE;
import static org.xdef.impl.compile.CompileBase.TEXT_MODE;
import static org.xdef.impl.compile.CompileBase.UNDEF_CODE;
import static org.xdef.impl.compile.CompileBase.genInternalMethod;
import static org.xdef.impl.compile.CompileBase.getClassTypeID;
import static org.xdef.impl.compile.CompileBase.getParser;
import static org.xdef.impl.compile.CompileBase.getTypeClass;
import static org.xdef.impl.compile.CompileBase.getTypeId;
import static org.xdef.impl.compile.CompileBase.getTypeMethod;
import static org.xdef.impl.compile.CompileBase.getTypeName;

/** Generation of compiler objects - variables, methods etc.
 * @author Trojan
 */
public final class CompileCode extends CompileBase {
	/** Internal stack size. */
	private final static int STACK_SIZE = 512; //20 for tests is enough!
	/** The parser (just for error reporting). */
	XScriptParser _parser;
	/** *  Mode of compilation:
* NO_MODE ... no mode
* TEXT_MODE ... text events
* ELEM_MODE ... element events
* GLOBAL_MODE ... global definitions
* ANY_MODE ... all modes */ byte _mode; /** Internal stack with item types. */ short[] _tstack; /** Internal stack with indexes to code constants * or -1 if stack item is a value, or -2 if optimizing is not allowed). */ int[] _cstack; /** Stack pointer (index to stack or -1). */ int _sp; /** Max. stack pointer. */ int _spMax; /** Index to last code item. */ int _lastCodeIndex; /** Address of code initialization. */ int _init; /** End address of code initialization. */ private int _initEnd; /** Actual index to last local variable. */ int _localVariablesLastIndex; /** Highest reached index to local variables. */ int _localVariablesMaxIndex; /** Switch to ignore unresolved externals */ boolean _ignoreUnresolvedExternals; /** Mode of external method interface: 0 - both modes, 1 - old, 2 - new. */ private final int _externalMode; /** Flag if warnings should be checked.*/ boolean _chkWarnings; /** Debug mode. */ boolean _debugMode; /** Array of external classes. */ Class[] _extClasses; /** Compiled code. */ final List _code; /** Table of local variables. */ Map _localVariables; /** External methods. */ private final Map _extMethods; /** Array of declared external methods. */ private final List _declaredMethods; /** List of actual NameSpace prefixes. */ Map _nsPrefixes; /** Table of NameSpace URIs. */ final List _namespaceURIs; /** Table of script methods */ private final Map _scriptMethods; /** Table of script global variables. */ XVariableTable _globalVariables; /** Variables block. */ XVariableTable _varBlock; /** Size of size of predefined global variables. */ private final int _globalPredefSize; /** Debug information. */ XDebugInfo _debugInfo = null; /** Components. */ final Map _components = new LinkedHashMap<>(); /** Binds. */ final Map _binds = new LinkedHashMap<>(); /** Enumerations. */ final Map _enums = new LinkedHashMap<>(); /** XDLexicon object (null if not specified). */ XDLexicon _lexicon = null; /** Flag if external method should be searched. */ private boolean _ignoreExternalMethods; /** Flag bindSet method is allowed. */ boolean _allowBindSet = false; /* Error id (to ensure to generate the unique identifier).*/ private int _errIdIndex = 1000; /** Creates a new instance of GenCodeObj. * @param extClasses Array of external classes. * @param externalMode id of mode external methods (old=1, new=2, both=0). * @param chkWarnings if false warnings are generated as error. * @param debugMode debug mode flag. * @param ignoreUnresolvedExternals ignore unresolved externals flag. */ CompileCode(final Class[] extClasses, final int externalMode, final boolean chkWarnings, final boolean debugMode, final boolean ignoreUnresolvedExternals) { // _spMax = 0; _parser = null; //java makes it _ignoreUnresolvedExternals = ignoreUnresolvedExternals; _externalMode = externalMode; _chkWarnings = chkWarnings; _debugMode = debugMode; _tstack = new short[STACK_SIZE]; _cstack = new int[STACK_SIZE]; _sp = -1; _lastCodeIndex = -1; _code = new ArrayList<>(); _localVariables = new LinkedHashMap<>(); _extMethods = new LinkedHashMap<>(); _declaredMethods = new ArrayList<>(); _scriptMethods = new LinkedHashMap<>(); _namespaceURIs = new ArrayList<>(); _globalVariables = _varBlock = new XVariableTable(null, 0); _localVariablesLastIndex = -1; _localVariablesMaxIndex = -1; _mode = NO_MODE; setExternals(extClasses); //external classes and/or objects _init = _initEnd = -1; //predefined global variables CompileVariable var = new CompileVariable("$stdOut", XD_OUTPUT, _globalVariables.getNextOffset(), (byte) 'G', null); var.setInitialized(true); _globalVariables.addVariable(var); var = new CompileVariable("$stdErr", XD_OUTPUT, _globalVariables.getNextOffset(), (byte) 'G', null); var.setInitialized(true); _globalVariables.addVariable(var); var = new CompileVariable("$stdIn", XD_INPUT, _globalVariables.getNextOffset(), (byte) 'G', null); var.setInitialized(true); _globalVariables.addVariable(var); var = new CompileVariable("$IDParser$", // use only internally XD_PARSER, _globalVariables.getNextOffset(), (byte) 'G', null); var.setInitialized(true); // prevent to report errors _globalVariables.addVariable(var); var = new CompileVariable("$IDuniqueSet$", // use only internally X_UNIQUESET_M, _globalVariables.getNextOffset(), (byte) 'G', null); var.setInitialized(true); // prevent to report errors _globalVariables.addVariable(var); _globalPredefSize = _globalVariables.getLastOffset(); } /** Reinitialize fields to prepare the recompilation of code. */ final void reInit() { clearLocalVariables(); _localVariablesMaxIndex = -1; _code.clear(); _lastCodeIndex = -1; _init = _initEnd = -1; _sp = -1; _spMax = 0; _globalVariables.setLastOffset(_globalPredefSize); for (ScriptMethod sm : _scriptMethods.values()) { sm.setAddr(-1); } for (XMVariable xmv: _globalVariables.toArray()) { CompileVariable v = (CompileVariable) xmv; if (v.getOffset() >= _globalPredefSize && !v.isConstant()) { //not predeclared v.setOffset(-1); v.setInitialized(false); } } } /** Gen error identifier.*/ final String genErrId() {return "#UNDEF#" + _errIdIndex++;} /** Set XScriptParser. */ final void setParser(final XScriptParser parser) {_parser = parser;} /** Clear local variables. */ final void clearLocalVariables() { _localVariables.clear(); _localVariablesLastIndex = -1; } /** Set flag to ignore external methods. * @param b flag to ignore external methods. */ final void setIgnoreExternalMethods(final boolean b) { _ignoreExternalMethods = b; } /** Add new variable of given name. * @param name the name of variable. * @param kind the variable kind ('G': global, 'L': local, 'X': XModel). * @param spos source position where the variable was declared. * @return the CompileVariable object. */ final CompileVariable addVariable(final String name, final short type, final byte kind, final SPosition spos) { if (type != X_PARSEITEM && getTypeId(name) >= 0) { //Type identifier '&{0}' can't be used here _parser.error(XDEF.XDEF463, name); return new CompileVariable("?", type, -1, (byte) 'L', spos); } CompileVariable result = null; switch (kind) { case 'G': result = (CompileVariable) _globalVariables.getVariable(name); if (result == null) { result = new CompileVariable(name, type, _globalVariables.getNextOffset(), kind, spos); _globalVariables.addVariable(result); return result; } else { if (result.getOffset() == -1) { if (result.resolvePostDef( _globalVariables.getNextOffset(), this)) { return result; } } } break; case 'X': if (_varBlock.getVariable(name) == null) { result = new CompileVariable(name, type, _varBlock.getNextOffset(), kind, spos); if (_varBlock.addVariable(result)) { return result; } } break; case 'L': result = _localVariables.get(name); if (result == null) { result = new CompileVariable(name, type, ++_localVariablesLastIndex, kind, spos); _localVariables.put(name, result); if (_localVariablesLastIndex > _localVariablesMaxIndex) { _localVariablesMaxIndex = _localVariablesLastIndex; } return result; } break; default: //Internal error&{0}{: } throw new SRuntimeException(SYS.SYS066, "variable kind: "+kind); } //Repeated declaration of variable '&{0}'&{#SYS000}&{1} //({; (already declared: }{)} putRedefinedError(null, XDEF.XDEF450, name, result == null ? null : result.getSourcePosition()); return (result != null && result.getName().equals(name) && result.getType() == type) ? result : new CompileVariable("?", type, -1, (byte) 'L', null); } /** Put error with the first declared item position. * @param actpos the actual source position or null. * @param id message ID. * @param name name of item. * @param sp Source position of declared item or null. */ final void putRedefinedError(final SPosition actpos, final long id, final String name, final SPosition sp) { String s = null; if (sp != null) { s = "line="+ sp.getLineNumber() + "; column=" + sp.getColumnNumber() + "; source=\"" + sp.getSystemId() + '"'; } //Redefinition of item '&{0}'&{#SYS000}&{1}({; (see: }{)} if (actpos == null) { _parser.error(id, name, s); //Redefinition of variable '&{0}' } else { _parser.error(actpos, id, name,s); //Redefinition of variable '&{0}' } } /** Check all unresolved declarations and try to resolve them. */ final void clearPostdefines() { for (ScriptMethod gm: _scriptMethods.values()) { gm.clearPostdefs(); //(should be already clear) } for (XMVariable xmv: _globalVariables.toArray()) { ((CompileVariable) xmv).clearPostdefs();// (should be already clear) } } /** Create string with list of parameter types from parameter list. * @param paramTypes list of types of parameters. * @return list of parameters converted to characters. */ private static String typeList(final short[] paramTypes) { if (paramTypes.length == 0) { return ""; } StringBuilder sb = new StringBuilder(paramTypes.length + 1).append('('); for (int i = 0; i < paramTypes.length; i++) { if (i > 0) { sb.append(','); } sb.append((char) paramTypes[i] + ' '); } return sb.append(')').toString(); } /** Create string with list of parameter types from stack. * @param numPar number of parameters. * @return string with characters of parameter types. */ private String typeList(final int numPar) { if (numPar == 0) { return ""; } StringBuilder sb = new StringBuilder(numPar + 1).append('('); for (int i = _sp - numPar + 1, j = i; i <= _sp; i++) { if (i > j) { sb.append(','); } sb.append((char) _tstack[i] + ' '); } return sb.append(')').toString(); } /** Set external classes. Adds externals to the list. * @param extObjects Array of external classes. */ final void setExternals(final Class... extObjects) { if (_extClasses == null) { _extClasses = _extClasses = new Class[0]; } if (extObjects != null && extObjects.length > 0) { List> ar = new ArrayList<>(Arrays.asList(_extClasses)); for (Class x: extObjects) { if (x != null && !ar.contains(x)) { ar.add(x); } } if (ar.size() != _extClasses.length) { _extClasses = ar.toArray(_extClasses); } } } /** Check if given identifier refers to a variable. * @param name The identifier of variable. * @return true if identifier refers to a variable. */ final boolean isVariable(final String name) { if (_localVariables.containsKey(name)) { return true; } if (_varBlock == null) { return false; } CompileVariable var = (CompileVariable)_varBlock.getXVariable(name); if (var == null || var.getKind() == 'G') { for (String s: _parser._importLocals) { CompileVariable v = (CompileVariable) _varBlock.getXVariable(s + name); if (v != null) { var = v; break; } } } if (var != null) { if (var.getOffset() == -1) { return false; } } return var != null; } /* Get declared variable. * @param name The name of variable. * @return declared variable or null. */ final CompileVariable getVariable(final String name) { CompileVariable var; var = _localVariables.get(name); if (var == null && _varBlock != null) { var = (CompileVariable) _varBlock.getXVariable(name); if (var == null || var.getKind() == 'G') { for (String s: _parser._importLocals) { CompileVariable v = (CompileVariable) _varBlock.getXVariable(s + name); if (v != null) { var = v; break; } } } if (var != null) { if (var.getOffset() == -1) { return null; } } } return var; } /** Get last code item. */ final XDValue getLastCodeItem() {return getCodeItem(_lastCodeIndex);} /** Remove last code item. */ final XDValue removeLastCodeItem() {return _code.remove(_lastCodeIndex--);} final XDValue getCodeItem(final int addr) { return (addr < 0 || addr >= _code.size()) ? null : _code.get(addr); } /** Replace last code item with new item. * @param item item which will replace the existing one. */ final void replaceLastCodeItem(final XDValue item) { if (_lastCodeIndex >= 0) { _code.set(_lastCodeIndex, item); } } /** Set code item on given index of code array. * @param index index to code array. * @param item item which will replace the existing one. */ final void setCodeItem(final int index, final XDValue item) { _code.set(index, item); } /** Replace last code item with the item given by argument. The code * of the item is changing the type of the top of the stack. * @param item The item which replaces the last code item. */ final void replaceTop(final XDValue item) { _tstack[_sp] = item.getItemId(); _code.set(_lastCodeIndex, item); _cstack[_sp] = (item.getCode() == LD_CONST) ? _lastCodeIndex : -1; } /** Replace two last code items with the item given by argument. The code * of the item is changing the type of the top of the stack. * @param item The item which replaces the last two code items. */ final void replaceTwo(final XDValue item) { _code.remove(_lastCodeIndex--); _sp--; replaceTop(item); } /** Create new undefined method. * @param name The name. * @param numPar Number of parameters. * @return undefined method object. */ private CodeExtMethod crtUndefMethod(final String name, final int numPar) { return new CodeExtMethod(name, XD_UNDEF, CompileCode.UNDEF_CODE, numPar, null); } /** Add code (stack not changed). * @param item The item to be added * throws SRuntimeException if stack overflow error occurs. */ final void addCode(final XDValue item) { _code.add(++_lastCodeIndex, item); } /** Add code (update stack pointer). * @param item The item to be added * @param stackInc Increment of the stack after execution of this item. * throws SRuntimeException if stack overflow error occurs. */ final void addCode(final XDValue item, final int stackInc) { addCode(item); if ((_sp += stackInc) > _spMax) { if (_sp >= STACK_SIZE) { //Overflow of compiler internal stack _parser.error(XDEF.XDEF204); _sp -= stackInc; return; } _spMax = _sp; } short type; if ((type = item.getItemId()) != XD_VOID) {//result is not void if (_sp >= 0) { _tstack[_sp] = type; _cstack[_sp] = (item.getCode()==LD_CONST) ? _lastCodeIndex : -1; } } } /** Add global method. * @param resultType The result type of method. * @param name The method name. * @param address The code index of method start. * @param params Array of parameters types. * @param mode The mode of method. * @param spos source position where the variable was declared. */ final void addMethod(final short resultType, final String name, final int address, final short[] params, final short mode, final SPosition spos) { String extName = name + typeList(params); ScriptMethod gm = _scriptMethods.get(extName); if (gm == null) { _scriptMethods.put(extName, new ScriptMethod(resultType, address, params, mode, spos)); } else if (!gm.resolvePostDef(address, this)) { //Repeated declaration of method '&{0}'&{#SYS000}&{1} //({; (already declared: }{)} putRedefinedError(null, XDEF.XDEF462, name, gm.getSourcePosition()); } } final Method addDeclaredMethod(final String name, final Method method) { Method m; if ((m = getDeclaredMethod(name, method.getParameterTypes())) != null) { return m; //ignore repeated declarations } _declaredMethods.add(new ExternalMethod(name, method)); return null; } private Method getDeclaredMethod(final String name,final Class[] params){ for (ExternalMethod d: _declaredMethods) { if (d.isMethod(name, params)) { return d.getMethod(); } } return null; } /** Find external method in the class and in super classes. * @param clazz Class to be inspected. * @name name of method. * @name parameters list of classes of parameters. * @return method or null. */ final Method getExtMethod(final Class clazz, final String name, final Class[] params) { if (clazz != null) { Method[] methods = clazz.getMethods(); for (Method m: methods) { if (name.equals(m.getName()) && (m.getModifiers() & Modifier.PUBLIC) != 0) { Class[] p = m.getParameterTypes(); if (p.length == params.length) { boolean paramsOK = true; for (int j = 0; j < p.length; j++) { Class param = params[j]; Class par = p[j]; if (!param.equals(par)) { if (!((param.equals(long.class) || param.equals(Long.class)) && (par.equals(Long.class) || par.equals(long.class) || par.equals(Integer.class) || par.equals(int.class))) && !((param.equals(double.class) || param.equals(double.class)) && (par.equals(Double.class) || par.equals(double.class) || par.equals(Float.class) || par.equals(float.class))) && !((param.equals(boolean.class) || param.equals(Boolean.class)) && (par.equals(boolean.class) || par.equals(Boolean.class)))) { paramsOK = false; break; } } } if (paramsOK) { return m; } } } } return null; } for (String s: _parser._importLocals) { Method m = getDeclaredMethod(s + name, params); if (m != null) { return m; } } return getDeclaredMethod(name, params); } /** Find external method in given class. * @param name The name of method. * @param numPar Number of parameters. * @param clazz The class. * @param obj instantiated object or null. * @return The object with external method call. */ final CodeExtMethod findExternalMethod(final String name, final int numPar, final Class clazz, final Object obj) { int modifiers; Method m = null; //static Method m1 = null; //not static short resultType = XD_UNDEF; short code = UNDEF_CODE; if (m == null && _externalMode != 1) {//new or both // 2.new style, params: type m([p1[,p2[, ... ]]]) Class[] params = new Class[numPar]; for (int j = 0; j < numPar; j++) { Class c = getTypeClass( (short) (_tstack[_sp - numPar+j+1] - XD_LONG + 1)); params[j] = c; } if ((m = getExtMethod(clazz, name, params)) != null) { modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } else { if ((resultType = getClassTypeID(m.getReturnType())) == XD_UNDEF) { code = UNDEF_CODE; m = null; } else { code = EXTMETHOD; modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } } } } } if (m == null && _externalMode != 1) {//new //new style, ChkElement and array: type m(ChkElement, DefItem[]) if ((m = getExtMethod(clazz, name, new Class[] {XXElement.class, XDValue[].class})) != null) { modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } else { if ((resultType = getClassTypeID(m.getReturnType())) == XD_UNDEF) { code = UNDEF_CODE; m = null; } else { code = EXTMETHOD_CHKEL_XDARRAY; modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } } } } if (m == null && (m = getExtMethod(clazz, name, new Class[] { XXNode.class, XDValue[].class})) != null) { modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } else { if ((resultType = getClassTypeID(m.getReturnType())) == XD_UNDEF) { code = UNDEF_CODE; m = null; } else { code = EXTMETHOD_XXNODE_XDARRAY; modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } } } } if (m == null && (m = getExtMethod(clazz, name, new Class[] { XXData.class, XDValue[].class})) != null) { modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } else { if ((resultType = getClassTypeID(m.getReturnType())) == XD_UNDEF) { code = UNDEF_CODE; m = null; } else { code = EXTMETHOD_XXNODE_XDARRAY; modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC)==0 && obj==null) { m1 = m; m = null; } } } } if (m == null && (m = getExtMethod(clazz, name, new Class[] { XDValue[].class})) != null) { modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } else { if ((resultType = getClassTypeID(m.getReturnType())) == XD_UNDEF) { code = UNDEF_CODE; m = null; } else { code = EXTMETHOD_XDARRAY; modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } } } } } if (m == null && _externalMode != 1) {//new //new style, XXNode and params: type m(XXNode[,p[,...]]) Class[] params = new Class[numPar + 1]; params[0] = XXNode.class; for (int j = 0; j < numPar; j++) { params[j + 1] = getTypeClass( (short) (_tstack[_sp-numPar+j+1] - XD_LONG + 1)); } if ((m = getExtMethod(clazz, name, params)) != null) { modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } else { if ((resultType = getClassTypeID(m.getReturnType())) == XD_UNDEF) { code = UNDEF_CODE; m = null; } else { code = EXTMETHOD_XXNODE; modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } } } } if (m == null) { params[0] = XXElement.class; if ((m = getExtMethod(clazz, name, params)) != null) { modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } else { if ((resultType=getClassTypeID(m.getReturnType())) == XD_UNDEF) { code = UNDEF_CODE; m = null; } else { code = EXTMETHOD_XXNODE; modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC)==0 && obj==null) { m1 = m; m = null; } } } } else { params[0] = XXData.class; if ((m = getExtMethod(clazz, name, params)) != null) { modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } else { if ((resultType = getClassTypeID(m.getReturnType())) == XD_UNDEF) { code = UNDEF_CODE; m = null; } else { code = EXTMETHOD_XXNODE; modifiers = m.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 && obj == null) { m1 = m; m = null; } } } } } } } if (m == null) { if (m1 != null) { //External method '&{0}' must be 'static' and 'public' _parser.error(XDEF.XDEF466, m1.getName()); m = m1; } } if (m != null) { return new CodeExtMethod(m.getDeclaringClass().getName()+'.'+name, resultType, code, numPar, m); } return null; } /** Get NameSpace context of this XElement. */ final KNamespace getXDNamespaceContext() { KNamespace result = new KNamespace(); for (Map.Entry item : _nsPrefixes.entrySet()) { String key = item.getKey(); if ("xml".equals(key) || "xmlns".equals(key) || XDConstants.XDEF31_NS_URI.equals( _namespaceURIs.get(item.getValue())) || XDConstants.XDEF32_NS_URI.equals( _namespaceURIs.get(item.getValue())) || XDConstants.XDEF40_NS_URI.equals( _namespaceURIs.get(item.getValue())) || XDConstants.XDEF41_NS_URI.equals( _namespaceURIs.get(item.getValue())) || XDConstants.XDEF42_NS_URI.equals( _namespaceURIs.get(item.getValue()))) { continue; } result.setPrefix(key, _namespaceURIs.get(item.getValue())); } return result; } /** Generate "stop" operation. */ final void genStop() {addCode(new CodeI1(XD_VOID, STOP_OP));} /** Add code for load attribute name. * @param name an attribute name. */ final void genLDAttr(final String name) { addCode(new CodeS1(XD_STRING, ATTR_REF, name)); if (++_sp > _spMax) { if (_sp >= STACK_SIZE) { //Overflow of compiler internal stack _parser.error(XDEF.XDEF204); _sp--; return; } _spMax = _sp; } _tstack[_sp] = X_ATTR_REF; _cstack[_sp] = -1; } /** Add code for load constant. * @param item The item to be added */ final void genLDC(final XDValue item) { addCode(item); if (++_sp > _spMax) { if (_sp >= STACK_SIZE) { //Overflow of compiler internal stack _parser.error(XDEF.XDEF204); _sp--; return; } _spMax = _sp; } _tstack[_sp] = item.getItemId(); _cstack[_sp] = _lastCodeIndex; } /** Add code for load variable. * @param name The name of local variable. * @return false if variable not exists. */ final boolean genLD(final String name) { CompileVariable var = getVariable(name); return var == null ? false : genLD(var); } /** Add code for load variable. * @param name The name of local variable. * @return false if variable not exists. */ final boolean genLD(final CompileVariable var) { short xType = var.getType(); if (xType == X_UNIQUESET_KEY) { return false; } if (!var.isInitialized()) { if (xType != X_PARSEITEM) { //Variable '&{0}' might be not initialized _parser.error(XDEF.XDEF464, var.getName()); } } short code; int addr = var.getOffset(); byte kind = var.getKind(); if (var.getCodeAddr() >= 0 && var.isFinal()) { code = LD_CODE; addr = var.getCodeAddr(); } else if (kind == 'G') { code = LD_GLOBAL; } else if (kind == 'X') { code = LD_XMODEL; } else { code = LD_LOCAL; } if (++_sp > _spMax) { if (_sp >= STACK_SIZE) { //Overflow of compiler internal stack _parser.error(XDEF.XDEF204); _sp--; return false; } _spMax = _sp; } _tstack[_sp] = xType; if (xType != X_UNIQUESET_NAMED && var.isConstant()) { addCode(var.getValue().cloneItem()); _cstack[_sp] = _lastCodeIndex; } else { addCode(new CodeS1(xType, code, addr, var.getName())); _cstack[_sp] = -1; } return true; } /** Add code for store value to local variable. * @param name The name of local variable. */ final void genST(final String name) { if (_sp >= 0) { short xType = _tstack[_sp]; CompileVariable var = getVariable(name); if (var == null) { _parser.error(XDEF.XDEF424, name);//Undefined variable &{0} var = addVariable(genErrId(), xType, (byte) 'L', null); } if (xType != var.getType()) { switch (xType) { case XD_DOUBLE: if (var.getType() == XD_LONG) { topToFloat(); break; } topToString(); break; case XD_STRING: topToString(); break; case XD_LONG: if (var.getType() == XD_DATETIME) { topToMillis(); } else if (xType == XD_DECIMAL) { addCode(new CodeI1(XD_DECIMAL, TO_DECIMAL_X, 0)); _cstack[_sp] = -1; return; } else if (var.getType() == XD_CHAR) { topXToInt(0); } break; case XD_ANY: break; case XD_UNDEF: return; case XD_PARSERESULT: convertTopToType(var.getType()); break; default: if (var.getType() != XD_ANY) { _parser.error(XDEF.XDEF457,//Incompatible types &{0} getTypeName(var.getType()) + "," + getTypeName(xType)); return; } } } genST(var); } } /** Add code for store value to local variable. * @param var CompileVariable object. */ final void genST(final CompileVariable var) { var.setInitialized(true); short code; short xType = var.getType(); switch (var.getKind()) { case 'G': code = ST_GLOBAL; break; case 'X': code = ST_XMODEL; break; default: code = ST_LOCAL; break; } addCode(new CodeS1(xType, code, var.getOffset(), var.getName())); _sp--; } /** Push on top of the stack the "undefined" value.*/ final void setUnDefItem() { _tstack[++_sp] = XD_UNDEF; _cstack[_sp] = -1; } /** Add jump to the end of code. * If argument is an unconditional jump return. If it is a conditional jump * then: *
  • 1. while the last code item is a logical 'not' operator reverse * jump true/false condition and remove the last 'not' code item. *
  • 2. if the last code item is a operator (CMPIEQ .. CMPDGT) then * replace it with the jump item object from argument. * If jump is JMPF operator reverse condition operator to logical * complement (i.e. CMPIEQ change to CMPINE, CMPDGT to CMPDLE etc). * Change code id of jump item from the argument to the last code item * converted to corresponding condition jump (CMPIEQ to JMPEQ etc) and * replace the last code item with it. Otherwise just add the jump item to * the end of code. * @param jump code object with a conditioned jump. */ final void addJump(final CodeI1 jump) { if (jump != null) { short jumpCode; if ((jumpCode = jump.getCode()) == JMP_OP) { addCode(jump, 0); return; } XDValue lastItem; short code; while (_lastCodeIndex >= 0 && (getLastCodeItem()).getCode() == NOT_B) { code = invertCode(jumpCode); if (code < 0) { break; } jump.setCode(jumpCode = code); _code.remove(_lastCodeIndex); _lastCodeIndex--; } if (_lastCodeIndex > 0) { lastItem = getLastCodeItem(); XDValue codeItem; if ((_sp < 0 || _cstack[_sp] != -2) && (code = lastItem.getCode()) >= CMPEQ && code <= CMPGT) { codeItem = (CodeI1) lastItem; if (jumpCode == JMPF_OP) { code = invertCode(((CodeI1) codeItem)._code); // JMPT_OP codeItem.setCode(code); } // convert cmpTxx -> jmpTxx jump.setCode((short) (code + JMPEQ - CMPEQ)); //replace last code _code.set(_lastCodeIndex, jump); //replace last code _sp--; return; } XDValue prevItem = getCodeItem(_lastCodeIndex - 1); if ((prevItem.getCode()) == LD_TRUE_AND_SKIP) { if (jumpCode == JMPF_OP) { setCodeItem(_lastCodeIndex - 1, //jump after last item new CodeI1(XD_VOID, JMP_OP, _lastCodeIndex + 1)); jump.setCode(JMP_OP); _code.set(_lastCodeIndex, jump); //replace last code } else { jump.setCode(JMP_OP); _code.remove(_lastCodeIndex--); _code.set(_lastCodeIndex, jump); //replace last code } _sp--; return; } } addCode(jump, -1); } } /** If jump vector is not empty generate boolean value from it. * @param jv CompileJumpVector object. */ final void jumpVectorToBoolValue(final CompileJumpVector jv) { if (!jv.isTrueJumpListEmpty()) { addJump(jv.addJumpItemToFalseList(JMPF_OP)); genBoolJumpConvertor(); jv.resoveTrueJumps(_lastCodeIndex - 1); jv.resoveFalseJumps(_lastCodeIndex); } else if (!jv.isFalseJumpListEmpty()) { addJump(jv.addJumpItemToFalseList(JMPF_OP)); genBoolJumpConvertor(); jv.resoveFalseJumps(_lastCodeIndex); } } /** Generate sequence of two operations: *
  • LD_TRUE_AND_SKIP_CODE, LDC_FALSE_CODE. */ final void genBoolJumpConvertor() { addCode(new CodeOp(XD_BOOLEAN, LD_TRUE_AND_SKIP)); addCode(new DefBoolean(false), 1); _cstack[_sp] = -1; } /** Check if code is an compare operation or conditional jump. * If yes, then the code is inverted to logical negation of given operation * and the method returns inverted code. Otherwise the method returns -1. * @param code inspected code. * @return inverted code or -1. */ private short invertCode(final short code) { switch (code) { case CMPEQ: // CMPxEQ -> CMPxNE case JMPEQ: // JMPxEQ -> JMPxNE case CMPGE: // CMPxGE -> CMPxLT case JMPGE: // JMPxGE -> JMPxLT case JMPF_OP: // JMPF -> JMPT return (short) (code + 1); case CMPNE: // CMPxNE -> CMPxEQ case JMPNE: // JMPxNE -> JMPxEQ case CMPLT: // CMPxLT -> CMPxGE case JMPLT: // JMPxLT -> JMPxGE case JMPT_OP: // JMPT -> JMPF return (short) (code - 1); case CMPLE: // CMPxLE -> CMPxGT case JMPLE: // JMPxLE -> JMPxGT return (short) (code + 3); case CMPGT: // CMPxGT -> CMPxLE case JMPGT: // JMPxGT -> JMPxLE return (short) (code - 3); default: return -1; } } /** Generate default conversion of the item on the top of stack. * @param resultType required type. */ final void convertTopToType(final short resultType) { short xType; if (_sp >= 0 && resultType != XD_UNDEF && resultType != (xType = _tstack[_sp])) { if (xType == resultType) { return; } if (xType == XD_UNDEF ||//do not report other error messages! resultType == XD_ANY) { _tstack[_sp] = resultType; return; } int xValue = _cstack[_sp]; if (xType == XD_NULL && xValue >= 0) { _code.set(xValue, DefNull.genNullValue(resultType)); _tstack[_sp] = resultType; return; } if (xType == XD_ANY) {//conversion from AnyValue //dynamic type check addCode(new CodeI1(resultType, CHECK_TYPE, resultType)); _tstack[_sp] = resultType; return; } switch (resultType) { case XD_STRING: topToString(); return; case XD_DOUBLE: if (xType == XD_LONG || xType == XD_DECIMAL) { topToFloat(); return; } break; case XD_LONG: switch (xType) { case XD_DATETIME: topToMillis(); return; case XD_DECIMAL: addCode(new CodeI1(XD_DECIMAL, TO_DECIMAL_X, 0)); _cstack[_sp] = -1; return; case XD_CHAR: topXToInt(0); return; } break; case XD_CHAR: if (xType == XD_LONG || xType == XD_DOUBLE || xType == XD_DECIMAL) { topXToChar(0); return; } break; case XD_DECIMAL: if (xType == XD_DOUBLE || xType == XD_LONG) { if (xValue >= 0) { _code.set(xValue, new DefDecimal( getCodeItem(xValue).decimalValue())); } else { addCode(new CodeI1(XD_DECIMAL, TO_DECIMAL_X, 0)); _cstack[_sp] = -1; } _tstack[_sp] = XD_DECIMAL; return; } break; case XD_BIGINTEGER: if (xType == XD_LONG) { if (xValue >= 0) { _code.set(xValue, new DefBigInteger( getCodeItem(xValue).integerValue())); } else { addCode( new CodeI1(XD_BIGINTEGER, TO_BIGINTEGER_X, 0)); _cstack[_sp] = -1; } _tstack[_sp] = XD_BIGINTEGER; return; } break; case XD_BOOLEAN: if (xType == X_ATTR_REF || xType == XD_PARSERESULT || xType == XD_PARSER) { topToBool(); return; } break; case XD_CONTAINER: addCode(new CodeI1(XD_CONTAINER, NEW_CONTAINER, 1)); _cstack[_sp] = -1; return; case XD_DATETIME: { break; } case XD_DURATION: { break; } case XD_ELEMENT: break; case XD_PARSERESULT: switch (xType) { case XD_PARSER: addCode(new CodeI1(XD_PARSERESULT,PARSE_OP,1),0); return; case XD_BOOLEAN: return; case XD_BNFRULE: addCode(new CodeI1(XD_PARSERESULT, BNFRULE_PARSE, 1), 0); _tstack[_sp] = XD_PARSERESULT; return; default: break; } break; default: } _parser.error(XDEF.XDEF457, //Incompatible types&{0}{: } getTypeName(xType) + "," + getTypeName(resultType)); _tstack[_sp] = XD_UNDEF; } } final void topToBool() { short xType; if (_sp >= 0 && XD_BOOLEAN != (xType = _tstack[_sp]) && XD_UNDEF != xType) { int codesize; CodeS1 cs; Object o; if (xType == X_ATTR_REF && (codesize = _code.size() - 1) >= 0 && (o = getCodeItem(codesize)) instanceof CodeS1 && (cs = (CodeS1) o)._code == ATTR_REF) { //attribute cs._code = ATTR_EXIST; _cstack[_sp] = -1; _tstack[_sp] = XD_BOOLEAN; } else if (xType == XD_PARSERESULT) { addCode(new CodeI1(XD_BOOLEAN, PARSERESULT_MATCH, 1)); _tstack[_sp] = XD_BOOLEAN; _cstack[_sp] = -1; } else if (xType == XD_PARSER) { addCode(new CodeI1(XD_BOOLEAN, PARSEANDCHECK, 1)); _tstack[_sp] = XD_BOOLEAN; _cstack[_sp] = -1; } else if (xType == XD_CONTAINER) { addCode(new CodeI1(XD_BOOLEAN, TO_BOOLEAN, 1)); _tstack[_sp] = XD_BOOLEAN; _cstack[_sp] = -1; } else { //Value of type '&{0}' expected _parser.error(XDEF.XDEF423,"boolean"); } } } /** Conversion of the stack item at top position to float. */ final void topToFloat() {topXToFloat(0);} /** Conversion of stack item under top to float. */ final void topXToFloat() {topXToFloat(1);} /** Conversion of stack item under top to int. */ final void topXToInt(final int index) { short xType; int sp = _sp - index; if (sp >= 0 && (xType = _tstack[sp]) != XD_LONG && xType != XD_UNDEF) { if (xType == XD_CHAR || xType == XD_DOUBLE || xType == XD_DECIMAL) { if (_cstack[sp] >= 0) { //constant _code.set(_cstack[sp], new DefLong( getCodeItem(_cstack[sp]).intValue())); } else { //value addCode(new CodeI1(XD_LONG, TO_INT_X, index)); _cstack[sp] = -1; } } else { //Value of type 'int' or 'float' expected _parser.error(XDEF.XDEF439); _cstack[sp] = -1; } _tstack[sp] = XD_LONG; } } /** Conversion of stack item under top to int. */ final void topXToChar(final int index) { short xType; int sp = _sp - index; if (sp >= 0 && (xType = _tstack[sp]) != XD_CHAR && xType != XD_UNDEF) { if (xType == XD_LONG || xType == XD_DOUBLE || xType == XD_DECIMAL){ if (_cstack[sp] >= 0) { //constant _code.set(_cstack[sp], new DefChar(getCodeItem(_cstack[sp]).intValue())); } else { //value addCode(new CodeI1(XD_LONG, TO_CHAR_X, index)); _cstack[sp] = -1; } } else { //Value of type 'int' or 'float' expected _parser.error(XDEF.XDEF439); _cstack[sp] = -1; } _tstack[sp] = XD_CHAR; } } /** Conversion of the stack item at top position to null or string. */ final void topToNullOrString() { short xType; if (_sp >= 0 && (xType=_tstack[_sp])!=XD_STRING && xType!=XD_UNDEF){ int xValue; if ((xValue = _cstack[_sp]) >= 0) {//constant if (xType == X_ATTR_REF) { _code.set(xValue, new CodeS1(XD_STRING, ATTR_REF, getCodeItem(xValue).stringValue())); _cstack[_sp] = -1; } else { //constant _code.set(xValue, new DefString(getCodeItem(xValue).stringValue())); } } else {//value addCode(new CodeI1(XD_STRING, NULL_OR_TO_STRING)); _cstack[_sp] = -1; } _tstack[_sp] = XD_STRING; } } /** Conversion of the stack item at top position to string. */ final void topToString() {topXToString(0);} /** Conversion of the given stack item to float. * @param index relative stack position from top. */ private void topXToFloat(final int index) { short xType; int sp = _sp - index; if (sp >= 0 && (xType=_tstack[sp])!=XD_DOUBLE && xType!=XD_UNDEF){ switch (xType) { case XD_LONG: if (_cstack[sp] >= 0) { //constant _code.set(_cstack[sp], new DefDouble( getCodeItem(_cstack[sp]).longValue())); } else { //value addCode(new CodeI1(XD_DOUBLE, TO_FLOAT_X, index)); _cstack[sp] = -1; } break; case XD_DECIMAL: if (_cstack[sp] >= 0) { //constant _code.set(_cstack[sp], new DefDouble( getCodeItem(_cstack[sp]).floatValue())); } else { //value addCode(new CodeI1(XD_DECIMAL, TO_DECIMAL_X, index)); _cstack[sp] = -1; } break; default: //Value of type 'int' or 'float' expected _parser.error(XDEF.XDEF439); _cstack[sp] = -1; break; } _tstack[sp] = XD_DOUBLE; } } /** Conversion of the given stack item to string. * @param index relative stack position from top. */ private void topXToString(final int index) { short xType; int sp = _sp - index; if (sp >= 0 && (xType=_tstack[sp])!=XD_STRING && xType!=XD_UNDEF){ int xValue; if ((xValue = _cstack[sp]) >= 0) {//constant if (xType == X_ATTR_REF) { _code.set(xValue, new CodeS1(XD_STRING, ATTR_REF, getCodeItem(xValue).stringValue())); _cstack[sp] = -1; } else { //constant _code.set(xValue, new DefString(getCodeItem(xValue).stringValue())); } } else {//value addCode(new CodeI1(XD_STRING, TO_STRING)); _cstack[sp] = -1; } _tstack[sp] = XD_STRING; } } /** Conversion of the stack item at top position to float. */ final void topToMillis() { short xType; if (_sp >= 0 && (xType=_tstack[_sp]) != XD_LONG && xType != XD_ANY && xType != XD_UNDEF) { if (xType == XD_DATETIME) { if (_cstack[_sp] >= 0) { //constant _code.set(_cstack[_sp], new DefLong( getCodeItem(_cstack[_sp]).datetimeValue(). getTimeInMillis())); } else { //value addCode(new CodeI1(XD_LONG, TO_MILLIS)); _cstack[_sp] = -1; } } else { //Value of type 'Datetime' or 'int' expected _parser.error(XDEF.XDEF441); _tstack[_sp] = XD_LONG; _cstack[_sp] = -1; } _tstack[_sp] = XD_LONG; } } /** Conversion of the part stack to Container. * @param index relative stack position from top. */ private void toContainer(final int n) { for (int i = 0; i < n; i++) { if (_cstack[_sp - i] < 0) { // not all constants addCode(new CodeI1(XD_CONTAINER, STACK_TO_CONTAINER, n), -n + 1); return; } } XDContainer c = new DefContainer(); for (int i = n - 1; i >= 0; i--) { c.addXDItem(_code.get(_lastCodeIndex)); _code.remove(_lastCodeIndex--); } _code.add(c); _sp = _sp - n + 1; _cstack[_sp] = ++_lastCodeIndex; _tstack[_sp] = XD_CONTAINER; } /** Generate conversion of two top stack items to float. */ final void operandsToFloat() { topXToFloat(1); topToFloat(); } /** Conversion of two top stack items to string. */ final void operandsToString() { topXToString(1); topToString(); } /** Remove code from codeIndex to end and clear associated stack. * @param codeIndex The point from which code is removed. * @param sp The saved stack pointer. * @param spMax The saved max. stack pointer. */ final void removeCodeFromIndexAndClearStack(final int codeIndex, final int sp, final int spMax) { for (int i = _lastCodeIndex; i > codeIndex; i--) { _code.remove(i); } _sp = sp; _spMax = spMax; _lastCodeIndex = codeIndex; for (int i = 0; i <= _sp; i++) { if (_cstack[i] > codeIndex) { _cstack[i] = -1; } } } /** Generate pop stack item (throw it away). */ final void genPop() { if (_sp >= 0) { addCode(new CodeI1(XD_VOID, POP_OP), -1); } } /** Generate duplicate stack item. */ final void genDup() { if (_sp >= 0) { short xType = _tstack[_sp]; if(xType == XD_LONG || xType == XD_BOOLEAN || xType == XD_DOUBLE || xType == XD_STRING) { addCode(new CodeI1(xType, STACK_DUP), 1); } else { //Internal error: &{0} _parser.error(SYS.SYS066, "Stack copy on type " + xType); } } } final boolean scriptMethod(final String name, final int numPar) { ScriptMethod lm = null; for (String s: _parser._importLocals) { lm = _scriptMethods.get(s + name); if (lm != null) { break; } } if (lm == null) { lm = _scriptMethods.get(name); if (lm == null) { return false; } } short[] pars = lm.getParams(); if (numPar != pars.length) { long errcode = numPar < pars.length ? XDEF.XDEF460 //More parameters required for method &{0} : XDEF.XDEF461;//Too many parameters for method &{0} _parser.error(errcode, name); } else { for (int i = numPar - 1, j = _sp; i >= 0; i--) { if (j < 0 || pars[i] != _tstack[j--]) { if (pars[i]!=XD_ANY && _tstack[j+1]!=XD_ANY && pars[i]!=XD_UNDEF &&_tstack[j+1]!=XD_UNDEF){ _parser.error(XDEF.XDEF467); //Incorrect parameter type } break; } } } CodeI1 operator = new CodeI1(lm.getResultType(), CALL_OP, lm.getAddr()); int np = numPar; if (lm.getResultType() != XD_VOID) { np--; } addCode(operator, -np); if (lm.getAddr() == -1) { lm.addPostDef(_lastCodeIndex); } return true; } final boolean externalMethod(final String name, final String extName, final int numPar) { if (_ignoreExternalMethods){ return false; } // try to find this method in XExtUtils class CodeExtMethod method = findExternalMethod(name, numPar, XExtUtils.class, null); if (method == null) { // not found, try to find it in the java.lang.Math class method = findExternalMethod(name, numPar, Math.class, null); if (method == null) { // not found, look to external methods list method = _extMethods.get(extName); if (method == null) { method = findExternalMethod(name, numPar, null, null); if (method == null && _extClasses != null) { // not found, try to find it in extternal classes for (Class extClass : _extClasses) { method = findExternalMethod(name, numPar, extClass,null); if (method != null) { _extMethods.put(extName, method); break; } } } if (method == null) { return false; // method was not found } } } } int np = numPar; if (method._resultType != XD_VOID) { np--; } addCode(method, -np); return true; } /** Generate method call. * @param name The name of method. * @param numPar Number of parameters (types of parameters are in stack). * @return name of the unknown method or null. */ final String genMethod(final String name, final int numPar) { String extName = name + typeList(numPar); if (extName.indexOf('?') >= 0) { //don't process searching of method with undefined parameter _sp -= numPar -1; _tstack[_sp] = XD_UNDEF; _cstack[_sp] = -1; return null; } CompileVariable var = getVariable(name); if (var != null) { int addr; if (var.getType() == X_PARSEITEM && numPar == 0 && var.getCodeAddr() == -1 && (addr = var.getParseMethodAddr()) >= 0 && _code.get(addr).getItemId() == XD_PARSER) { if (var.getKind()=='G' && _code.get(addr).getCode()==LD_CONST && addr + 2 <= _lastCodeIndex && _code.get(addr+1).getCode() == PARSE_OP && _code.get(addr+2).getCode() == STOP_OP) { _cstack[++_sp] = addr; addCode(new CodeS1(XD_PARSER, LD_CODE, addr, name)); addCode(new CodeI1(XD_PARSERESULT, PARSE_OP, 1), 0); } else { addCode(new CodeI1(XD_PARSERESULT, CALL_OP, addr), 1); } return null; //OK } else if (var.getType() == X_UNIQUESET && var.getCodeAddr() == -1 || var.getType() == X_PARSEITEM && numPar == 0) { //check type ID (unique type, unique value) addCode(new CodeI1(XD_BOOLEAN, CALL_OP, var.getParseMethodAddr()), 1); // return null if it is OK, otherwise return method name return numPar != 0 ? name : null; } } if (scriptMethod(extName, numPar) || numPar > 0 && _tstack[_sp] == XD_CONTAINER && scriptMethod(name + typeList(numPar), numPar) || externalMethod(name, extName, numPar) || internalMethod(name, numPar)) { return null; } String s = null; if (!_ignoreUnresolvedExternals) { //create string with the method name and the list of parameter types s = name + "("; for (int i = _sp - numPar + 1, j = i; i <= _sp; i++) { if (i > j) { s += ','; } short type = _tstack[i]; s += type == X_ATTR_REF ? "String" : getTypeName(type); } s += ')'; } //generate dummy code. CodeExtMethod method = crtUndefMethod(name, numPar); _extMethods.put(name+extName, method); int np = numPar; if (method._resultType != XD_VOID) { np--; } addCode(method, -np); return s; // null if it is OK, othrwise it is error message } /** Put report XDEF998 "{0}" is deprecated. Please use "&{1}" instead. * @param old old text. * @param replace text to be deprecated/ */ final void reportDeprecated(final String old, final String replace) { if (_chkWarnings) { _parser.warning(XDEF.XDEF998, '"' + old + '"', '"' + replace + '"'); } } /** Generation of internal method code. * @param name The name of method. * @param numPar Number of parameters (types of parameters are in stack). */ final boolean internalMethod(final String name, final int numPar) { CompileBase.InternalMethod imethod = getTypeMethod(X_NOTYPE_VALUE, name); if (imethod == null) { return false; } if (imethod.isDeprecated()) { reportDeprecated(name, imethod.getRecommendedName()); } genInternalMethod(name, numPar, imethod); return true; } final boolean genConstructor(final short type, final int numPar) { if (type == XD_UNDEF) { if (_sp >= 0) { _cstack[_sp] = -1; } return true; //do not report multiple errors! } CompileBase.InternalMethod imethod = getTypeMethod(type, "#"); if (imethod == null) { return false; } if (imethod.isDeprecated()) { reportDeprecated(getTypeName(type), imethod.getRecommendedName()); } genInternalMethod(getTypeName(type), numPar, imethod); return true; } final boolean genClassMethod(final String name, final int numPar) { if (_sp - numPar < 0) { return false; } short xType = _tstack[_sp - numPar]; if (xType == XD_VOID || xType == XD_UNDEF) { if (xType == XD_VOID) { _parser.error(XDEF.XDEF438); //Value expected } return true; } else if (xType < 0 || xType >= X_NOTYPE_VALUE) { return false; } else if ("equals".equals(name) && numPar == 1) { addCode(new CodeI1(XD_BOOLEAN, EQUALS_OP, 1), -1); _cstack[_sp] = -1; topToBool(); return true; } else if ("toString".equals(name) && numPar == 0) { topToString(); return true; } else if ("exists".equals(name) && xType == X_ATTR_REF && numPar == 0){ topToBool(); return true; } CompileBase.InternalMethod imethod = getTypeMethod(xType, name); if (imethod == null && xType == XD_PARSER) { addCode(new CodeI1(XD_PARSERESULT, PARSE_OP, 1), 0); xType = _tstack[_sp - numPar]; imethod = getTypeMethod(xType, name); } if (imethod != null) { if (imethod.isDeprecated()) { reportDeprecated(name, imethod.getRecommendedName()); } genInternalMethod(name, numPar + 1, imethod); return true; } return false; } /** This method is called only for GET_XPATH and GET_XPATH_FROM_SOURCE! * @param npar number of parameters. * @param code code to be optimized. * @return true if code was optimized. */ private boolean optimizeXPath(final int npar, final short code) { int sp = code == GET_XPATH ? _sp-npar+1 : _sp; int constPar = _cstack[sp]; if (constPar < 0) { return false; // xpath expression is not string constant } String s = getCodeItem(constPar).toString(); if (s == null || (s = s.trim()).isEmpty()) { //XPath error&{0}{: } _parser.error(XML.XML505, "empty argument"); return false; } int ix = s.charAt(0) == '@' ? 1 : s.startsWith("self::") ? 6 : 0; String name = s.substring(ix); ix = StringParser.chkXMLName(name, (byte) 10) ? !name.contains("::") ? ix : -1 : -1; if (ix < 0) { return false; } if (npar == 2) { if (code == GET_XPATH) { if (constPar + 1 != _lastCodeIndex) { return false; } XDValue v = _code.get(_lastCodeIndex); //element value //relace code with string constant _code.set(constPar++, v); _tstack[_sp - 1] = _tstack[_sp]; //should be element _cstack[_sp - 1] = _cstack[_sp]; } sp = --_sp; } int ndx = name.indexOf(':'); if (ndx > 0) { // has prefix -> namespaceURI String prefix = name.substring(0, ndx); String uri = getXDNamespaceContext().getNamespaceURI(prefix); name = '{' + uri + '}' + name.substring(ndx+1); } else if (ix != 1) { // not attribute -> may have defalut namespace String uri = getXDNamespaceContext().getNamespaceURI(""); if (uri != null) { name = '{' + uri + '}' + name; } } switch (ix) { case 1: //@name->String _code.set(constPar, new CodeS1(XD_CONTAINER, GETATTR_FROM_CONTEXT, npar,name)); _tstack[sp] = XD_CONTAINER; break; case 6: // self::name -> element _code.set(constPar, new CodeS1(XD_CONTAINER, GETELEM_FROM_CONTEXT, npar,name)); _tstack[sp] = XD_CONTAINER; break; default: // name -> Container _code.set(constPar, new CodeS1(XD_CONTAINER, GETELEMS_FROM_CONTEXT,npar,name)); _tstack[sp] = XD_CONTAINER; break; } _cstack[sp] = -1; return true; } /** Set sequential parameter as named parameter. * @param d Container with parameters. * @param val value of parameter. * @param name name of named parameter. */ private void setSeqParam(final XDContainer d, final XDValue val, final String name) { if (d.hasXDNamedItem(name)) { //Conflict of sequential parameter and named parameter: &{0} _parser.error(XDEF.XDEF442, name); } if (!val.isNull()) { // ignore it if it is null d.setXDNamedItem(name, val); } } /** Generation of internal method code. * @param name The name of method. * @param numPar Number of parameters (types of parameters are in stack). * @param imethod The internal method descriptor. */ private void genInternalMethod(final String name, final int numPar, final CompileBase.InternalMethod imethod) { short code = imethod.getCode(); int npar = numPar; //is modified, should be local //first parameter type short par1typ = npar > 0 ? _tstack[_sp - (npar - 1)] : -1; //first parameter value constant pointer or -1 int par1const = npar > 0 ? _cstack[_sp - (npar - 1)] : -1; CompileBase.InternalMethod method = imethod; short resultType = method.getResultType(); XDValue operator = null; switch (code) { case FROM_ELEMENT://deprecated reportDeprecated("fromElement", "from"); break; case LD_CONST: { if (resultType != XD_PARSER) { //Internal error: &{0} _parser.error(XDEF.XDEF202,"const type: "+resultType); break; // this should never happen! } // parsers if (npar == 0) { // no parameters if ("string".equals(name) || "CDATA".equals(name)) { genLDC(getParser("CDATA")); } else { if (imethod.getMinParams() > 0) { //More parameters required for method &{0} _parser.error(XDEF.XDEF460, name); } genLDC(getParser(name)); } return; } else if ("list".equals(name) && //deprecated! par1typ != XD_CONTAINER && par1typ != XD_PARSER) { reportDeprecated("list", "enum"); genInternalMethod("enum", npar, getTypeMethod(X_NOTYPE_VALUE, "enum")); return; } XDParser p = getParser("CDATA".equals(name) ? "string" : name); CompileBase.KeyParam[] pars = method.getKeyParams(); String[] sqParamNames = method.getSqParamNames(); if (npar == 1 && _tstack[_sp] == XD_CONTAINER && _cstack[_sp] == _lastCodeIndex) {// set named parameters DefContainer h = (DefContainer) getLastCodeItem(); int len = h.getXDNamedItemsNumber(); // check named parameters for (int i = len - 1; i >= 0; i--) { String s = h.getXDNamedItemName(i); boolean found = false; for (CompileBase.KeyParam par : pars) { if (par.getName().equals(s)) { XDValue[] legal = par.getLegalValues(); if (legal != null && legal.length > 0) { XDValue v = h.getXDNamedItemValue(s); boolean found1 = false; for (int k = 0; k < legal.length; k++) { if (legal[k].equals(v)) { if (k == 0) {// default h.removeXDNamedItem(s); len--; } found1 = true; } } if (!found1) { //Incorrect value of '&{0}'&{1}{: } _parser.error(XDEF.XDEF809, s); } } found = true; break; } } if (!found) { //Illegal parameter name '&{0}' _parser.error(XDEF.XDEF801, s); } } for (CompileBase.KeyParam par: pars) { String parName = par.getName(); XDNamedValue val = h.getXDNamedItem(parName); boolean err = false; XDValue v = val != null ? val.getValue() : null; if (v != null && "base".equals(parName)) { if (v.getItemId() == XD_BOOLEAN) { val.setValue(v.booleanValue() ? new XDParseTrue() : new XDParseFalse()); } else if (v.getItemId() != XD_PARSER) { err = true; } } else if (v != null && "item".equals(parName)) { if (v.getItemId() == XD_CONTAINER) { for (XDValue x:((XDContainer)v).getXDItems()){ if (x.getItemId() != XD_PARSER) { err = true; break; } } } else if (v.getItemId() != XD_PARSER) { err = true; } } if (err) { //The value type in the named parameter '&{0}' // of the parser&{1}{ '}{'} must be Parser _parser.error(XDEF.XDEF474, "%item",p.parserName()); } if (par.isFixed()) { if (val == null) { h.setXDNamedItem(parName,par.getDefaultValue()); len++; } else if (!val.equals(par)) { //Incorrect value of '&{0}'&{1}{: } _parser.error(XDEF.XDEF809, parName, "\"" + val + '"'); } } else if (par.isRequired() && val == null) { //Missing required parameter: &{0} _parser.error(XDEF.XDEF545, parName); } } if (len > 0) { try { p.setNamedParams(null, h); } catch (Exception ex) { if (ex instanceof SThrowable) { _parser.putReport(((SThrowable)ex).getReport()); } else if (ex instanceof ClassCastException) { //Incorrect parameter type _parser.error(XDEF.XDEF467); } else { _parser.putReport( //Internal error&{0}{: } Report.error(SYS.SYS066, ex, ex)); } } } else if ("datetime".equals(name) || "xdatetime".equals(name)) { //More parameters required for method &{0} _parser.error(XDEF.XDEF460, "xdatetime"); } _code.set(_lastCodeIndex, p); _tstack[_sp] = resultType; } else { if (_tstack[_sp] == XD_CONTAINER) { if (npar-1 > sqParamNames.length) { //Too many parameters for method &{0} _parser.error(XDEF.XDEF461, name); } } else if (npar > method.getMaxParams()) { //Too many parameters for method &{0} _parser.error(XDEF.XDEF461, name); } boolean allconst = true; for (int i = 0; i < npar; i++) { if (_cstack[_sp-i] != _lastCodeIndex - i) { allconst = false; // not constant break; } } if (_tstack[_sp] != XD_CONTAINER) { if ("string".equals(name)) { p = new XDParseCDATA(); } if (npar > sqParamNames.length && sqParamNames.length == 1) { toContainer(npar); npar = 1; if (allconst) { XDValue val = removeLastCodeItem(); _sp--; XDContainer d = new DefContainer(); d.setXDNamedItem(sqParamNames[0], val); try { p.setNamedParams(null, d); genLDC(p); return; } catch (Exception ex) {} //never happens } else { addCode(new CodeS1(XD_NAMEDVALUE, CREATE_NAMEDVALUE, sqParamNames[0]),0); addCode(new CodeParser(resultType, NEW_PARSER, npar, p.parserName(), sqParamNames), -npar + 1); } return; } } if (allconst) { XDValue val = removeLastCodeItem(); _sp--; XDContainer d; if (val.getItemId() == XD_CONTAINER) { d = (XDContainer) val; if (--npar >= 1) { val = removeLastCodeItem(); _sp--; } } else { d = new DefContainer(); //empty map } if (npar > 0 && npar <= 2 && sqParamNames!=null && sqParamNames.length == 2){ String s1 = sqParamNames[0]; //1. parameter name String s2 = sqParamNames.length > 1 ? sqParamNames[1] : s1; //2. parameter name if (npar-- == 1) {// only one sequential parameter if (sqParamNames.length > 1 && s1.startsWith("min") && s2.startsWith("max")) { setSeqParam(d, val, s1); setSeqParam(d, val, s2); } else { setSeqParam(d, val, s1); } } else {// two sequential parameters setSeqParam(d, val, s2); npar--; val = removeLastCodeItem(); // first parameter _sp--; setSeqParam(d, val, s1); } } else { if (sqParamNames==null || npar > sqParamNames.length) { //Too many of sequential parameters _parser.error(XDEF.XDEF465); } else { while (--npar > 0) { setSeqParam(d, val, sqParamNames[npar]); val = removeLastCodeItem(); _sp--; } setSeqParam(d, val, sqParamNames[0]); } } try { if (!d.isEmpty()) { XDValue minlen = d.getXDNamedItemValue("minLength"); XDValue maxlen = d.getXDNamedItemValue("maxLength"); if (minlen != null && maxlen != null && minlen.equals(maxlen)) { if (d.hasXDNamedItem("length")) { //Conflict of sequential parameter //and named parameter: &{0} _parser.error(XDEF.XDEF442, "length"); } d.removeXDNamedItem("minLength"); d.removeXDNamedItem("maxLength"); d.setXDNamedItem("length", minlen); } p.setNamedParams(null, d); } } catch (Exception ex) { if (ex instanceof SThrowable) { _parser.putReport(((SThrowable)ex).getReport()); } else { //Incorrect parameter value _parser.error(XDEF.XDEF471); } } genLDC(p); } else { addCode(new CodeParser(resultType, NEW_PARSER, npar, p.parserName(), sqParamNames), -npar + 1); } } return; } case UNIQUESET_BIND: if (_mode != imethod.getRestrictions() || !_allowBindSet) { //Method '&{0}' not allowed here _parser.error(XDEF.XDEF472, name); code = UNDEF_CODE; } _allowBindSet = false; break; case GET_DBQUERY: { if (npar < 1) { break; } if (par1typ == XD_SERVICE) { if (npar == 1) { //The argument with query statement is missing _parser.error(XDEF.XDEF111); } } else if (par1typ != XD_STATEMENT) { //The first argument of the method 'dbquery' must be either // DBconnection or XIterator _parser.error(XDEF.XDEF110); break; } // check modification parameters for (int i = _sp - npar + 2; i <= _sp; i++) { if (_tstack[i] != XD_STRING) { //The argument &{0} must be of &{1} type _parser.error(XDEF.XDEF112, i-(_sp-npar)-1, "String"); } } break; } case SET_ATTR: case GET_ATTR: case HAS_ATTR: case DEL_ATTR: case CREATE_ELEMENTS: case CREATE_ELEMENT: { int xpar = code == CREATE_ELEMENTS ? 2 : code == CREATE_ELEMENT ? 1 : code == SET_ATTR ? 3 : 2; if (npar == xpar && _cstack[_sp] >= 0 && _tstack[_sp] == XD_STRING) { String qname = getCodeItem(_cstack[_sp]).toString(); int i; String prefix = (i = qname.indexOf(':')) >= 0 ? qname.substring(0, i) : ""; Integer p = _nsPrefixes.get(prefix); if (p == null) { if (prefix.length() > 0) { //Namespace for prefix '&{0}' isn't defined _parser.error(XDEF.XDEF257, prefix); } } else { npar++; genLDC(new DefString(_namespaceURIs.get(p))); } } break; } case GET_XPATH: if (npar == 2) { short typ2 = _tstack[_sp]; if (typ2 != XD_CONTAINER && typ2 != XD_ELEMENT) { //Parameter type must be XML Node _parser.error(XDEF.XDEF113); } if (par1typ != XD_STRING) { //Value of type '&{0}' expected _parser.error(XDEF.XDEF423, "String"); } else if (par1const >= 0) { if (optimizeXPath(npar, code)) { return; } try { DefXPathExpr xp = new DefXPathExpr( getCodeItem(par1const).toString(), getXDNamespaceContext(), null, null); xp.setCode(LD_CONST); _code.set(par1const, xp); _cstack[_sp-1] = -1; } catch (SRuntimeException ex) { _parser.putReport(ex.getReport()); } } break; } case GET_XPATH_FROM_SOURCE: if (npar == 1 || npar == 2) { if (_tstack[_sp] != XD_STRING) { //Value of type '&{0}' expected _parser.error(XDEF.XDEF423, "String"); } else if (optimizeXPath(npar, code)) { return; } if (npar == 2) { if (par1typ != XD_ELEMENT) { //Value of type '&{0}' expected _parser.error(XDEF.XDEF423, "Element"); } if (_cstack[_sp] == _lastCodeIndex) { // COMPILE_XPATH -> vynechat String s = getCodeItem(_lastCodeIndex).toString(); DefXPathExpr xp = new DefXPathExpr(s, getXDNamespaceContext(), null, null); if (s.indexOf(':') < 0) { xp.setCode(LD_CONST); } _code.set(_lastCodeIndex, xp); _tstack[_sp] = XD_XPATH; _cstack[_sp] = -1; } operator = new CodeI1(resultType, code, npar); addCode(operator, -1); //npar-1 return; } } break; case GET_XQUERY: if (npar == 1 || npar == 2) { int cnstLast = _cstack[_sp]; if (_tstack[_sp] != XD_STRING) { //Value of type '&{0}' expected _parser.error(XDEF.XDEF423, "String"); } else if (cnstLast >= 0) { try { _code.set(cnstLast, new DefXQueryExpr( getCodeItem(cnstLast).toString())); } catch (SRuntimeException ex) { _parser.putReport(ex.getReport()); } } if (npar == 2) { if (par1typ != XD_ELEMENT) { //Value of type '&{0}' expected _parser.error(XDEF.XDEF423, "Element"); } operator = new CodeI1(resultType, code, npar); npar--; addCode(operator, -npar); return; } } break; case GET_NS: if (npar == 2) { if (par1typ != XD_ELEMENT) { _parser.error(XDEF.XDEF467); //Incorrect parameter type } topToString(); } else if (npar == 1) { if (par1typ != XD_ELEMENT) { topToString(); } } break; case SET_ELEMENT: if (npar == 1) { if (par1typ != XD_CONTAINER && par1typ != XD_ELEMENT) { //Parameter type must be 'Container' or 'Element' _parser.error(XDEF.XDEF468); break; } } break; case GET_ELEMENT: if (npar > 0) {//getElement(list, index) method = getTypeMethod(X_NOTYPE_VALUE, "#getElement"); code = method.getCode(); resultType = method.getResultType(); } break; case CONTEXT_GETTEXT: if (npar == 0) {//getText() method = getTypeMethod(X_NOTYPE_VALUE, "#getValue"); code = method.getCode(); resultType = method.getResultType(); } break; case TO_STRING: //NOTE this case item continues (without break) if (npar == 2) { topToString(); switch (_tstack[_sp - 1]) { case XD_LONG: code = INTEGER_FORMAT; method.getParamTypes()[0] = INTEGER_FORMAT; break; case XD_DOUBLE: code = FLOAT_FORMAT; break; case XD_DATETIME: code = DATE_FORMAT; if(_cstack[_sp] >= 0) { Report r = StringParser.checkDateFormat( getCodeItem(_cstack[_sp]).toString()); if (r != null) { _parser.error(r.getMsgID(), r.getText(), r.getModification()); } } break; case XD_ANY: break; default: //Format mask supported only for numbers or dates _parser.error(XDEF.XDEF469); } method = genInternalMethod(code, XD_STRING, method.getRestrictions(), 2, 2, //min. number and max. number of parameters _tstack[_sp - 1], // first parameter type XD_STRING); // second parameter type break; } if (npar != 1) { if (npar == 0) { _parser.error(XDEF.XDEF459); //Parameter is missing return; } } topToString(); return; case TO_FLOAT: case TO_MILLIS: if (npar != 1) { if (npar == 0) { _parser.error(XDEF.XDEF459); //Parameter is missing return; } } if (code == TO_FLOAT) { topToFloat(); } else { topToMillis(); } return; case OUTLN_STREAM: case OUT_STREAM: if (npar == 1) { topToString(); } break; case OUTLN1_STREAM: case OUT1_STREAM: if (npar == 2) { topToString(); } break; case PRINTF_STREAM: { int maskPar; if (_tstack[_sp - npar + 1] == XD_OUTPUT) { if (npar == 2) { //More parameters required for method &{0} _parser.error(XDEF.XDEF460, "printf"); return; } maskPar = _sp - npar + 2; } else { maskPar = _sp - npar + 1; } if (_tstack[maskPar] == XD_LOCALE) { maskPar++; } if (_tstack[maskPar] != XD_STRING) { //Value of type '&{0}' expected _parser.error(XDEF.XDEF423,"String"); return; } break; } case FORMAT_STRING: { int maskPar = _sp - npar + 1; if (_tstack[_sp - npar + 1] == XD_LOCALE) { maskPar++; } if (_tstack[maskPar] != XD_STRING) { //Value of type '&{0}' expected _parser.error(XDEF.XDEF423, "String"); return; } break; } case PUT_ERROR: if (npar > 0) { if (_tstack[_sp + 1 - npar] == XD_OUTPUT) { //first param if (npar < 2) { //More parameters required for method &{0} _parser.error(XDEF.XDEF460, name); return; } else if (npar > 4) { //Too many parameters for method &{0} _parser.error(XDEF.XDEF461, name); return; } method = getTypeMethod(XD_OUTPUT, "error"); code = PUT_ERROR1; } else { if (npar > 1 && _tstack[_sp] == XD_REPORT) { //Too many parameters for method &{0} _parser.error(XDEF.XDEF461, name); return; } if (npar > 3) { //Too many parameters for method &{0} _parser.error(XDEF.XDEF461, name); return; } } } break; case COMPILE_REGEX: if (npar == 1) { if (_tstack[_sp] != XD_STRING) { //Value of type '&{0}' expected _parser.error(XDEF.XDEF423, "String"); return; } if (par1const >= 0) {//constant try { replaceTop(new DefRegex( getCodeItem(par1const).toString())); } catch (Exception ex) { if (ex instanceof SThrowable) { _parser.putReport(((SThrowable)ex).getReport()); } else { //Incorrect regular expression _parser.error(XDEF.XDEF650, ex); } } return; } } break; case PARSE_FLOAT: case PARSE_INT: case PARSE_DATE: if (numPar != 2) { topToString(); break; } operandsToString(); int par2const = _cstack[_sp]; if (par2const >= 0) {//format mask Report r = StringParser.checkDateFormat( _code.get(par2const).toString()); if (r != null) {// incorrect mask _parser.error(r.getMsgID(), r.getText(), r.getModification()); return; } } if(par1const >= 0 && par2const >= 0) { //both are literals StringParser p = new StringParser( _code.get(par1const).toString()); //mask if (!p.isDatetime(_code.get(par2const).toString())) { _parser.error("XDEF499","Incorrect value of date/time"); return; } replaceTwo(new DefDate(p.getParsedSDatetime())); return; } break; case GET_ATTR_NAME: if((_mode & (TEXT_MODE)) == 0) { //Method '&{0}' can't be called here _parser.error(XDEF.XDEF475, "&getAttrName"); } break; case GET_BNFRULE: { if (npar == 2 && //BNFGRAMMAR_VALUE, XD_STRING par1typ == XD_BNFGRAMMAR && //BNF grammar) _cstack[_sp] >= 0 && _tstack[_sp] == XD_STRING) { //rulename XDValue v = getCodeItem(_lastCodeIndex - 1); if (v.getCode() == LD_GLOBAL) { CompileVariable xv = (CompileVariable) _globalVariables.getXVariable(v.getParam()); v = xv.getValue(); } else if (v.getCode() != LD_CODE) { v = null; } if (v != null && v instanceof XDBNFGrammar) { XDBNFGrammar g = (XDBNFGrammar) v; String ruleName = getCodeItem(_cstack[_sp]).toString(); XDBNFRule r = g.getRule(ruleName); if (r == null || r.ruleValue() == null) { //BNF rule '&{0}' not exists _parser.error(XDEF.XDEF108, ruleName); } } } break; } case NEW_BNFGRAMAR: { if (npar == 1 && par1const >= 0 && par1typ == XD_STRING) { //string constant in BNF contructor SBuffer source = new SBuffer( getCodeItem(par1const).stringValue(), _parser); DefBNFGrammar dd; try { dd = new DefBNFGrammar(null, -1, source, _parser.getReportWriter()); } catch (SRuntimeException ex) { //error was reported to reporter; dd = new DefBNFGrammar(); dd.setParam(-1); dd.setSource(source.getString()); } _code.set(_lastCodeIndex, dd); _tstack[_sp] = resultType; _cstack[_sp] = _lastCodeIndex; //constant! return; } break; } case NEW_LOCALE: { String lang = getCodeItem(par1const).toString(); if (npar == 1 && par1const >= 0) { replaceTop(new DefLocale(lang)); _tstack[_sp] = XD_LOCALE; _cstack[_sp] = _lastCodeIndex; //constant! return; } else if (npar == 2 && par1const >= 0 && _cstack[_sp] >= 0) { String country = getCodeItem(_cstack[_sp]).toString(); replaceTwo(new DefLocale(lang, country)); _tstack[_sp] = XD_LOCALE; _cstack[_sp] = _lastCodeIndex; //constant! return; } else if (npar == 3 && par1const >= 0 && _cstack[_sp - 1] >= 0 && _cstack[_sp] >= 0) { String country = getCodeItem(_cstack[_sp - 1]).toString(); String variant = getCodeItem(_cstack[_sp]).toString(); _code.remove(_lastCodeIndex--); _code.remove(_lastCodeIndex--); _sp -= 2; replaceTop(new DefLocale(lang, country, variant)); return; } } case SET_NAMEDVALUE: { if (npar == 2) { if (_tstack[_sp] == XD_CONTAINER) { //???? } else if (_tstack[_sp] != XD_NAMEDVALUE) { //Value of type '&{0}' expected _parser.error(XDEF.XDEF423, "NamedValue"); } } else if (npar == 3) { if (_tstack[_sp - 1] != XD_STRING) { //Value of type '&{0}' expected _parser.error(XDEF.XDEF423, "String"); } } break; } default: } //check parameters if ((method.getRestrictions() & _mode) == 0) { _parser.error(XDEF.XDEF472, name);//Method '&{0}' not allowed here code = UNDEF_CODE; resultType = XD_UNDEF; } else if (npar < method.getMinParams()) { //More parameters required for method &{0} _parser.error(XDEF.XDEF460, name); code = UNDEF_CODE; resultType = XD_UNDEF; } else if (npar > method.getMaxParams()) { if (method.getMaxParams() == 0) { //Parameters are not allowed for method '&{0}' _parser.error(XDEF.XDEF473, name); } else { //Too many parameters for method &{0} _parser.error(XDEF.XDEF461, name); } code = UNDEF_CODE; resultType = XD_UNDEF; } else if (method.getParamTypes() != null) { short mtype = XD_ANY; for (int i = 0; i < npar; i++) { if (i < method.getParamTypes().length) { mtype = method.getParamTypes()[i]; } int j = _sp + i + 1 - npar; short ptype; if (mtype != XD_ANY && mtype != (ptype = _tstack[j])) { if (ptype != XD_ANY && ptype != XD_UNDEF) { if (mtype == XD_DOUBLE && ptype == XD_LONG) { if (npar - 1 - i == 0) { topToFloat(); } else { topXToFloat(npar - 1 - i); } } else { //Incorrect parameter type _parser.error(XDEF.XDEF467); code = UNDEF_CODE; resultType = XD_UNDEF; break; } } } } } if (operator == null) { operator = new CodeI1(resultType, code, npar); } if (resultType != XD_VOID) { npar--; } addCode(operator, -npar); } //////////////////////////////////////////////////////////////////////////////// // Methods for generation of initialization code. //////////////////////////////////////////////////////////////////////////////// /** Return the code item with the last stop of the initialization code * sequence or return null. */ final CodeI1 getLastStop() { //prevents to generate redundant jumps. if (_lastCodeIndex != -1 && _initEnd >= 0) { if (_lastCodeIndex != _initEnd) { return (CodeI1) getCodeItem(_initEnd); } _code.remove(_lastCodeIndex--); } return null; } /** Add initialization code. */ final void addInitCode(final int actAdr, final CodeI1 lastStop) { if (actAdr == _lastCodeIndex + 1) { genStop(); } else if (actAdr < _lastCodeIndex) { //gen init section if (_init == -1) { _init = actAdr + 1; } else if (lastStop != null) { lastStop._code = JMP_OP; //change it to jump to next addr lastStop.setParam(actAdr + 1); } genStop(); _initEnd = _lastCodeIndex; } } } /** Object describing a script method. */ final class ScriptMethod { /** The offset of method. */ private int _address; /** The List of types of parameters. */ private final short[] _params; /** The type of result of method. */ private final short _resultType; /** The compilation mode of method (the purpose). */ private final short _mode; /** List of code code addresses where method was called. */ private int[] _postdefs; /** Source position where the method was declared. */ private final SPosition _spos; /** Create new instance of ScriptMethod. * @param resultType The result type of method. * @param address The code index of method start. * @param params Array of parameters types. * @param mode The mode of method. * @param spos source position where the method was declared. */ ScriptMethod(final short resultType, final int address, final short[] params, final short mode, final SPosition spos) { _resultType = resultType; _address = address; _params = params; _mode = mode; _postdefs = null; _spos = spos; } /** Add address of post defined item to the list. */ final void addPostDef(final int codeIndex) { if (_postdefs == null) { _postdefs = new int[]{codeIndex}; } else { int[] x = _postdefs; int len = x.length; _postdefs = new int[len + 1]; System.arraycopy(x, 0, _postdefs, 0, len); _postdefs[len] = codeIndex; } } /** Resolves post-definition of a method (set address to all previous * references). * @param address address of method. * @param g code generator. * @return false if address was already set(i.e. error), * otherwise return true (i.e. OK). */ final boolean resolvePostDef(final int address, final CompileCode g) { if (_address != -1) { return false; } _address = address; if (_postdefs != null) { for (int pc: _postdefs) { ((CodeI1) g.getCodeItem(pc)).setParam(address); } _postdefs = null; } return true; } /** Get result type of method. */ final short getResultType() {return _resultType;} /** Get address of method. */ final int getAddr() {return _address;} /** Set address of method. * @param address the address. */ final void setAddr(final int address) {_address = address;} /** Get array with the list of parameter types. */ final short[] getParams() {return _params;} /** Get address of method. */ final short getMode() {return _mode;} /** Clear post-definition info. */ final void clearPostdefs() {_postdefs = null;} /** Get source position where the method was declared. * @return source position where the method was declared. */ final SPosition getSourcePosition() {return _spos;} @Override public final String toString() { String result = getTypeName(_resultType) + " x("; if (_params != null) { for (short par : _params) { if (!result.endsWith("x(")) { result += ", "; } result += getTypeName(par); } } return result + ')'; } } /** Object containing the external method. */ final class ExternalMethod { /** Name of method (may be alias). */ private final String _name; /** External method. */ private final Method _method; /** Parameters of method. */ private final Class[] _mparams; /** Constructor. */ ExternalMethod(final String name, final Method method) { _method = method; _name = name; _mparams = _method.getParameterTypes(); } /** Check if this is a method. */ final boolean isMethod(final String name, final Class[] params) { if (!_name.equals(name)) { return false; } if (_mparams.length != params.length) { return false; } for (int i = 0; i < _mparams.length; i++) { Class x = _mparams[i]; Class y = params[i]; if (y.equals(Long.TYPE) && (x.equals(Long.TYPE) || x.equals(Long.class) || x.equals(Integer.TYPE) || x.equals(Integer.class) || x.equals(Short.TYPE) || x.equals(Short.class) || x.equals(Byte.TYPE) || x.equals(Byte.class)) || y.equals(Double.TYPE) && (x.equals(Double.TYPE) || x.equals(Double.class) || x.equals(Float.TYPE) || x.equals(Float.class)) || y.equals(Boolean.TYPE) && (x.equals(Boolean.TYPE) || x.equals(Boolean.class))) { continue; } if (!x.equals(y)) { return false; } } return true; } /** Get external method. * @return Java external method object. */ final Method getMethod() {return _method;} @Override public final String toString() {return _name + "; " + _method;} }




  • © 2015 - 2024 Weber Informatics LLC | Privacy Policy