Added String.fromCharCode, "a".code

Added a preprocessor
This commit is contained in:
NeeEoo
2024-04-25 17:23:35 +02:00
parent 6c77566fea
commit fb8f35e2a5
11 changed files with 277 additions and 111 deletions
+67
View File
@@ -0,0 +1,67 @@
/*
* Copyright (C)2008-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package hscript;
#if hscriptPos
class Error {
public var e : ErrorDef;
public var pmin : Int;
public var pmax : Int;
public var origin : String;
public var line : Int;
public function new(e, pmin, pmax, origin, line) {
this.e = e;
this.pmin = pmin;
this.pmax = pmax;
this.origin = origin;
this.line = line;
}
public function toString(): String {
return Printer.errorToString(this);
}
}
enum ErrorDef
#else
enum Error
#end
{
EInvalidChar( c : Int );
EUnexpected( s : String );
EUnterminatedString;
EUnterminatedComment;
EInvalidPreprocessor( msg : String );
EUnknownVariable( v : String );
EInvalidIterator( v : String );
EInvalidOp( op : String );
EInvalidAccess( f : String );
ECustom( msg : String );
EPreset( msg : ErrorMessage );
EInvalidClass( className : String);
EAlreadyExistingClass( className : String);
EInvalidEscape( s : String );
}
enum abstract ErrorMessage(String) to String {
final INVALID_CHAR_CODE_MULTI = "'char'.code only works on single characters";
final FROM_CHAR_CODE_NON_INT = "String.fromCharCode only works on integers";
final EMPTY_INTERPOLATION = "Invalid interpolation: Expression cannot be empty";
}
-38
View File
@@ -139,44 +139,6 @@ enum CType {
CTNamed( n : String, t : CType );
}
#if hscriptPos
class Error {
public var e : ErrorDef;
public var pmin : Int;
public var pmax : Int;
public var origin : String;
public var line : Int;
public function new(e, pmin, pmax, origin, line) {
this.e = e;
this.pmin = pmin;
this.pmax = pmax;
this.origin = origin;
this.line = line;
}
public function toString(): String {
return Printer.errorToString(this);
}
}
enum ErrorDef
#else
enum Error
#end
{
EInvalidChar( c : Int );
EUnexpected( s : String );
EUnterminatedString;
EUnterminatedComment;
EInvalidPreprocessor( msg : String );
EUnknownVariable( v : String );
EInvalidIterator( v : String );
EInvalidOp( op : String );
EInvalidAccess( f : String );
ECustom( msg : String );
EInvalidClass( className : String);
EAlreadyExistingClass( className : String);
EInvalidEscape( s : String );
}
enum ModuleDecl {
DPackage( path : Array<String> );
DImport( path : Array<String>, ?everything : Bool );
+6 -1
View File
@@ -158,6 +158,11 @@ class Interp {
variables.set("null", null);
variables.set("true", true);
variables.set("false", false);
#if !NO_FROM_CHAR_CODE_FIX
variables.set("__StringWorkaround__fromCharCode", function(a:Int) { // TODO: make hscript only add this if its used
return String.fromCharCode(a);
});
#end
variables.set("trace", Reflect.makeVarArgs(function(el) {
var inf = posInfos();
var v = el.shift();
@@ -472,7 +477,7 @@ class Interp {
}
}
public inline function error(e:#if hscriptPos ErrorDef #else Error #end, rethrow = false):Dynamic {
public inline function error(e:#if hscriptPos Error.ErrorDef #else Error #end, rethrow = false):Dynamic {
#if hscriptPos var e = new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line); #end
if (rethrow) {
+12
View File
@@ -163,6 +163,14 @@ class Parser {
opPriority.set(x, x == "++" || x == "--" ? -1 : -2);
}
public static inline function getBaseError( err ):Error {
#if hscriptPos
return new Error(err, 0, 0, "", 0);
#else
return err;
#end
}
public inline function error( err, pmin, pmax ) {
if( !resumeErrors )
#if hscriptPos
@@ -215,6 +223,7 @@ class Parser {
parseFullExpr(a);
}
var expr = if( a.length == 1 ) a[0] else mk(EBlock(a),0);
expr = Preprocessor.process(expr);
if(Parser.optimize) {
expr = Optimizer.optimize(expr);
var printer = new Printer();
@@ -1880,6 +1889,9 @@ class Parser {
interpString.push(arr);
interpolation = false;
if(arr.length == 2) // If its just ()
error(EPreset(EMPTY_INTERPOLATION), p1, p1);
if( StringTools.isEof(peekChar()) )
break;
+58
View File
@@ -0,0 +1,58 @@
package hscript;
import hscript.Expr;
import hscript.Error;
import hscript.Tools;
import hscript.Parser;
@:access(hscript.Parser)
class Preprocessor {
static inline function expr(e:Expr) return Tools.expr(e);
/**
* Preprocesses the expression, like 'a'.code => 97
* Also for transforming any abstracts into their implementations (TODO)
* Also for transforming any static extensions into their real form (TODO)
**/
public static function process(e:Expr, doBlock:Bool = true):Expr {
if(e == null)
return null;
trace(expr(e));
e = Tools.map(e, function(e) {
return process(e);
});
switch(expr(e)) {
case EField(expr(_) => EConst(CString(s)), "code", _): // Transform string.code into charCode
if(s.length != 1) {
throw Parser.getBaseError(EPreset(INVALID_CHAR_CODE_MULTI));
}
return mk(EConst(CInt(s.charCodeAt(0))), e);
case ECall(expr(_) => EField(expr(_) => EIdent("String"), "fromCharCode", _), [e]):
switch(expr(e)) {
case EConst(CInt(i)):
return mk(EConst(CString(String.fromCharCode(i))), e);
default:
// __StringWorkaround__fromCharCode(i);
#if !NO_FROM_CHAR_CODE_FIX
return mk(ECall(mk(EIdent("__StringWorkaround__fromCharCode"), e), [e]), e);
#else
throw Parser.getBaseError(EPreset(FROM_CHAR_CODE_NON_INT));
#end
}
default:
}
return e;
}
static function mk(e:ExprDef, s:Expr):Expr {
#if hscriptPos
return new Expr(e, s.pmin, s.pmax, s.origin, s.line);
#else
return e;
#end
}
}
+8 -3
View File
@@ -513,12 +513,16 @@ class Printer {
}
}
public static function toString( e : Expr ) {
public inline static function toString( e : Expr ) {
return new Printer().exprToString(e);
}
public static function errorToString( e : Expr.Error ) {
var message = switch( #if hscriptPos e.e #else e #end ) {
public inline static function compareErrors( e1 : Error, e2 : Error ) {
return Type.enumEq(Tools.cleanError(e1), Tools.cleanError(e2));
}
public static function errorToString( e : Error ) {
var message = switch( Tools.cleanError(e) ) {
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
case EUnexpected(s): "Unexpected token: \""+s+"\"";
case EUnterminatedString: "Unterminated string";
@@ -529,6 +533,7 @@ class Printer {
case EInvalidOp(op): "Invalid operator: "+op;
case EInvalidAccess(f): "Invalid access to field " + f;
case ECustom(msg): msg;
case EPreset(msg): msg;
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
case EInvalidEscape(s): "Invalid escape sequence: " + s;
+8
View File
@@ -107,6 +107,14 @@ class Tools {
#end
}
public static inline function cleanError( e : Error ) {
#if hscriptPos
return e.e;
#else
return e;
#end
}
public static inline function mk( e : ExprDef, p : Expr ):Expr {
#if hscriptPos
return new Expr(e, p.pmin, p.pmax, p.origin, p.line);