Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions hscript/Ast.hx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ enum ExprDef {
EDoWhile(cond:Expr, body:Expr);
EMeta(name:String, args:Array<Expr>, expr:Expr);
EImport(path:String, mode:EImportMode);
EClass(name:VariableType, decl:ClassDecl);

EInfo(info:VariableInfo, expr:Expr);
EEmpty;
Expand Down Expand Up @@ -266,10 +267,41 @@ enum EImportMode {
All; // import haxe.*;
}

class ImportInfo {
public var path:String;
public var mode:EImportMode;

public function new(path:String, mode:EImportMode) {
this.path = path;
this.mode = mode;
}
}

class ClassDecl {
public var name:String;
public var extend:Null<String>;
public var implement:Array<String>;
public var body:Expr; // Will be always EInfo along with a EBlock
public var isFinal:Bool;

public function new(name:String, ?extend:String, implement:Array<String>, body:Expr, isFinal:Bool) {
this.name = name;
this.extend = extend;
this.implement = implement;
this.body = body;
this.isFinal = isFinal;
}
}

typedef VariableType = Int;
typedef VariableInfo = Array<String>;

interface IHScriptCustomBehaviour {
public function hset(name:String, value:Dynamic):Dynamic;
public function hget(name:String):Dynamic;
}

//@:build(insert macro here...)
interface IHScriptClass extends IHScriptCustomBehaviour {
public var instance:hscript.misc.classes.Instance;
}
78 changes: 61 additions & 17 deletions hscript/Interp.hx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package hscript;

import hscript.Ast.ImportInfo;
import hscript.misc.classes.ClassHandler;
import hscript.Ast.ClassDecl;
import haxe.ds.ObjectMap;
import haxe.ds.Map;
import haxe.ds.StringMap;
Expand Down Expand Up @@ -65,6 +68,9 @@ class ScriptRuntime {
private var variableNames:Vector<String>;
private var variablesLookup:StringMap<Int>;

@:allow(hscript.misc.classes.ClassHandler)
private var importLookup:StringMap<ImportInfo>;

private var changes:Array<IDeclaredVariable> = [];

private var depth:Int = 0;
Expand Down Expand Up @@ -123,6 +129,8 @@ class ScriptRuntime {
this.variableNames = null;
this.variablesLookup = null;

this.importLookup = null;

this.changes = [];

this.variables.useDefaults = true;
Expand All @@ -141,6 +149,8 @@ class ScriptRuntime {
variableNames = Vector.fromArrayCopy(info);
variablesLookup = new StringMap<Int>();
for (i => name in info) variablesLookup.set(name, i);

importLookup = new StringMap<ImportInfo>();
}

private function loadBaseVariables() {
Expand Down Expand Up @@ -212,6 +222,20 @@ class ScriptRuntime {
return ref.r;
}

private inline function declarePublic(name:VariableType, value:Dynamic):Bool {
if(publicVariables == null) return false;
var varName:String = variableNames[name];
publicVariables.set(varName, value);
return true;
}

private inline function declareStatic(name:VariableType, value:Dynamic):Bool {
var varName:String = variableNames[name];
if(StaticInterp.staticVariables.exists(varName)) return false;
StaticInterp.staticVariables.set(varName, value);
return true;
}

private inline function assign(name:VariableType, value:Dynamic):Dynamic {
variablesDeclared[name] = true;
variablesValues[name].r = value;
Expand Down Expand Up @@ -322,15 +346,10 @@ class Interp extends ScriptRuntime {
case EIdent(name): if (variablesDeclared[name]) variablesValues[name].r; else resolveGlobal(name);
case EVar(name, init, isPublic, isStatic):
if (depth == 0) {
var varName:String = variableNames[name];
if (isStatic && !StaticInterp.staticVariables.exists(varName)) {
StaticInterp.staticVariables.set(varName, interpExpr(init));
if (isStatic && declareStatic(name, interpExpr(init)))
return null;
}
if (isPublic && publicVariables != null) {
publicVariables.set(varName, interpExpr(init));
if (isPublic && declarePublic(name, interpExpr(init)))
return null;
}
}
declare(name, init == null ? null : interpExpr(init));
return null;
Expand Down Expand Up @@ -446,6 +465,9 @@ class Interp extends ScriptRuntime {
var importValue:Dynamic = interpImport(path, mode);
if (importValue == null) error(EInvalidClass(path), expr.line);
return importValue;
case EClass(name, decl):
interpClass(name, decl);
return null;
case EInfo(info, _): error(ECustom("Invalid EInfo()"), expr.line);
case EEmpty: null;
}
Expand Down Expand Up @@ -485,6 +507,7 @@ class Interp extends ScriptRuntime {
return null;
}

// TODO: resolve custom class
private function interpImport(path:String, mode:EImportMode):Dynamic {
if (mode == All) return null; // not implemented

Expand All @@ -502,7 +525,7 @@ class Interp extends ScriptRuntime {
if (variablesDeclared[variableID]) return variablesValues[variableID].r;
}

var testClass:Either<Class<Dynamic>, Enum<Dynamic>> = StaticInterp.resolvePath(path);
var testClass:EitherOfThree<Class<Dynamic>, Dynamic, Enum<Dynamic>> = StaticInterp.resolvePath(path);
if (testClass == null) {
var splitPathCopy:Array<String> = splitPathName.copy();
splitPathCopy.splice(-2, 1);
Expand All @@ -514,11 +537,14 @@ class Interp extends ScriptRuntime {
if (testClass != null) {
var value:Dynamic = switch (testClass) {
case Left(resolvedClass): resolvedClass;
case Middle(resolvedValue): resolvedValue;
case Right(rawEnum): StaticInterp.resolveEnum(rawEnum);
}

if (variablesLookup.exists(variableName))
declare(variablesLookup.get(variableName), value);
else if(!importLookup.exists(variableName)) // cache the import
importLookup.set(variableName, new ImportInfo(splitPathName.join("."), mode));

return value;
}
Expand Down Expand Up @@ -600,13 +626,12 @@ class Interp extends ScriptRuntime {
functionRef.r = reflectiveFunction;
if (name != -1) {
if (depth == 0) {
var varName:String = variableNames[name];
if (isStatic && !StaticInterp.staticVariables.exists(varName)) {
StaticInterp.staticVariables.set(varName, reflectiveFunction);
if (isStatic) {
declareStatic(name, reflectiveFunction);
return reflectiveFunction;
}
if (isPublic && publicVariables != null) {
publicVariables.set(variableNames[name], reflectiveFunction);
if (isPublic) {
declarePublic(name, reflectiveFunction);
return reflectiveFunction;
}
}
Expand Down Expand Up @@ -749,9 +774,15 @@ class Interp extends ScriptRuntime {
if (classType == null) classType = resolveGlobal(className);

var params:Array<Dynamic> = [for (arg in args) interpExpr(arg)];
if(classType is ClassHandler)
return ClassHandler.createInstance(classType, params);
return Type.createInstance(classType, params);
}

private inline function interpClass(name:VariableType, decl:ClassDecl) {
declare(name, new ClassHandler(decl, this));
}

private function assignExpr(left:Expr, right:Expr):Dynamic {
var assignValue:Dynamic = interpExpr(right);
switch (left.expr) {
Expand Down Expand Up @@ -843,8 +874,16 @@ class Interp extends ScriptRuntime {
}
}

private enum EitherOfThree<L, M, R> {
Left(v:L);
Middle(v:M);
Right(v:R);
}

class StaticInterp {
public static var staticVariables:StringMap<Dynamic> = new StringMap<Dynamic>();
public static var staticVariables:StringMap<Dynamic> = new StringMap<Dynamic>();

public static var pathResolver:String -> Dynamic = null;

public static inline function evaluateBinop(op:ExprBinop, val1:Dynamic, val2:Dynamic):Dynamic {
switch (op) {
Expand Down Expand Up @@ -901,7 +940,7 @@ class StaticInterp {
}
}

// https://github.com/HaxeFoundation/hscript/blob/master/hscript/Interp.hx#L646-L652
// https://github.com/HaxeFoundation/hscript/blob/master/hscript/Interp.hx#L677-L683
public static inline function getMapValue(map:Dynamic, key:Dynamic):Dynamic {
return cast(map, IMap<Dynamic, Dynamic>).get(key);
}
Expand All @@ -910,13 +949,18 @@ class StaticInterp {
cast(map, IMap<Dynamic, Dynamic>).set(key, value);
}

public static function resolvePath(path:String):Either<Class<Dynamic>, Enum<Dynamic>> {
public static function resolvePath(path:String):EitherOfThree<Class<Dynamic>, Dynamic, Enum<Dynamic>> {
var resolvedClass:Class<Dynamic> = Type.resolveClass(path);
if (resolvedClass != null) return Left(resolvedClass);

var resolvedEnum:Enum<Dynamic> = Type.resolveEnum(path);
if (resolvedEnum != null) return Right(resolvedEnum);

if(pathResolver != null) {
var resolvedValue:Dynamic = pathResolver(path);
if(resolvedValue != null) return Middle(resolvedValue);
}

return null;
}

Expand Down Expand Up @@ -1075,4 +1119,4 @@ class InterpLocalsImpl {
public inline function exists(key:String):Bool {
return parent.variablesLookup != null && parent.variablesLookup.exists(key) && parent.variablesDeclared[parent.variablesLookup.get(key)];
}
}
}
7 changes: 5 additions & 2 deletions hscript/Lexer.hx
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,12 @@ enum abstract LKeyword(String) from String {
var CASE:LKeyword = "case";
var CAST:LKeyword = "cast";
var CATCH:LKeyword = "catch";
var HCLASS:LKeyword = "class";
var CONTINUE:LKeyword = "continue";
var DEFAULT:LKeyword = "default";
var DO:LKeyword = "do";
var ELSE:LKeyword = "else";
var HEXTENDS:LKeyword = "extends";
var FALSE:LKeyword = "false";
var FINAL:LKeyword = "final";
var FOR:LKeyword = "for";
Expand All @@ -198,6 +200,7 @@ enum abstract LKeyword(String) from String {
var HIMPORT:LKeyword = "import"; // HIMPORT to prevent conflicts with lua libs
var IN:LKeyword = "in";
var HINLINE:LKeyword = "inline"; // HINLINE to prevent conflicts with lua libs
var HIMPLEMENTS:LKeyword = "implements";
var NEW:LKeyword = "new";
var NULL:LKeyword = "null";
var OVERRIDE:LKeyword = "override";
Expand All @@ -214,8 +217,8 @@ enum abstract LKeyword(String) from String {
var WHILE:LKeyword = "while";

public static final ALL_KEYWORDS:Array<LKeyword> = [
AS, BREAK, CASE, CAST, CATCH, CONTINUE, DEFAULT, DO, ELSE,
FALSE, FINAL, FOR, FUNCTION, IF, HIMPORT, IN, HINLINE,
AS, BREAK, CASE, CAST, CATCH, HCLASS, CONTINUE, DEFAULT, DO, ELSE, HEXTENDS,
FALSE, FINAL, FOR, FUNCTION, IF, HIMPORT, IN, HINLINE, HIMPLEMENTS,
NEW, NULL, OVERRIDE, PRIVATE, PUBLIC, RETURN, STATIC,
SWITCH, THIS, THROW, TRUE, TRY, VAR, WHILE
];
Expand Down
Loading