static FxExpression *ParseAtan2(FScanner &sc, FName identifier, PClassActor *cls) { FxExpression *a = ParseExpressionM(sc, cls); sc.MustGetToken(','); FxExpression *b = ParseExpressionM(sc, cls); sc.MustGetToken(')'); return identifier == NAME_ATan2 ? new FxATan2(a, b, sc) : new FxATan2(b, a, sc); }
static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls) { FxExpression *condition = ParseExpressionL (sc, cls); if (sc.CheckToken('?')) { FxExpression *truex = ParseExpressionM (sc, cls); sc.MustGetToken(':'); FxExpression *falsex = ParseExpressionM (sc, cls); return new FxConditional(condition, truex, falsex); } else { return condition; } }
FxExpression *ParseExpression (FScanner &sc, PClassActor *cls) { FxExpression *data = ParseExpressionM (sc, cls); FCompileContext ctx(cls); data = data->Resolve(ctx); return data; }
static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls) { FxExpression *src = ParseExpressionM(sc, cls); sc.MustGetToken(','); FxExpression *min = ParseExpressionM(sc, cls); sc.MustGetToken(','); FxExpression *max = ParseExpressionM(sc, cls); sc.MustGetToken(')'); // Build clamp(a,x,y) as min(max(a,x),y) TArray<FxExpression *> list(2); list.Reserve(2); list[0] = src; list[1] = min; FxExpression *maxexpr = new FxMinMax(list, NAME_Max, sc); list[0] = maxexpr; list[1] = max; return new FxMinMax(list, NAME_Min, sc); }
static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cls) { FRandom *rng = ParseRNG(sc); sc.MustGetToken('('); FxExpression *min = ParseExpressionM (sc, cls); sc.MustGetToken(','); FxExpression *max = ParseExpressionM (sc, cls); sc.MustGetToken(')'); if (identifier == NAME_Random) { return new FxRandom(rng, min, max, sc); } else { return new FxFRandom(rng, min, max, sc); } }
static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cls) { TArray<FxExpression*> list; for (;;) { FxExpression *expr = ParseExpressionM(sc, cls); list.Push(expr); if (sc.CheckToken(')')) break; sc.MustGetToken(','); } return new FxMinMax(list, identifier, sc); }
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls) { FRandom *rng = ParseRNG(sc); FxExpression *mask = NULL; sc.MustGetToken('('); if (!sc.CheckToken(')')) { mask = ParseExpressionM(sc, cls); sc.MustGetToken(')'); } return new FxRandom2(rng, mask, sc); }
static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls) { FxExpression *base_expr = ParseExpression0 (sc, cls); while(1) { FScriptPosition pos(sc); #if 0 if (sc.CheckToken('.')) { if (sc.CheckToken(TK_Default)) { sc.MustGetToken('.'); base_expr = new FxClassDefaults(base_expr, pos); } sc.MustGetToken(TK_Identifier); FName FieldName = sc.String; pos = sc; /* later! if (SC_CheckToken('(')) { if (base_expr->IsDefaultObject()) { SC_ScriptError("Cannot call methods for default."); } base_expr = ParseFunctionCall(base_expr, FieldName, false, false, pos); } else */ { base_expr = new FxDotIdentifier(base_expr, FieldName, pos); } } else #endif if (sc.CheckToken('[')) { FxExpression *index = ParseExpressionM(sc, cls); sc.MustGetToken(']'); base_expr = new FxArrayElement(base_expr, index); } else break; } return base_expr; }
static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor *cls) { bool floaty = identifier == NAME_FRandomPick; FRandom *rng; TArray<FxExpression*> list; list.Clear(); int index = 0; rng = ParseRNG(sc); sc.MustGetToken('('); for (;;) { FxExpression *expr = ParseExpressionM(sc, cls); list.Push(expr); if (sc.CheckToken(')')) break; sc.MustGetToken(','); } return new FxRandomPick(rng, list, floaty, sc); }
static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls) { FxExpression *x = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return new FxAbs(x); }
static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) { FScriptPosition scpos(sc); if (sc.CheckToken('(')) { FxExpression *data = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return data; } else if (sc.CheckToken(TK_True)) { return new FxConstant(1, scpos); } else if (sc.CheckToken(TK_False)) { return new FxConstant(0, scpos); } else if (sc.CheckToken(TK_IntConst)) { return new FxConstant(sc.Number, scpos); } else if (sc.CheckToken(TK_FloatConst)) { return new FxConstant(sc.Float, scpos); } else if (sc.CheckToken(TK_NameConst)) { return new FxConstant(sc.Name, scpos); } else if (sc.CheckToken(TK_StringConst)) { // String parameters are converted to names. Technically, this should be // done at a higher level, as needed, but since no functions take string // arguments and ACS_NamedExecuteWithResult/CallACS need names, this is // a cheap way to get them working when people use "name" instead of 'name'. return new FxConstant(FName(sc.String), scpos); } else if (sc.CheckToken(TK_Identifier)) { FName identifier = FName(sc.String); FArgumentList *args; PFunction *func; switch (identifier) { case NAME_Random: case NAME_FRandom: return ParseRandom(sc, identifier, cls); case NAME_RandomPick: case NAME_FRandomPick: return ParseRandomPick(sc, identifier, cls); case NAME_Random2: return ParseRandom2(sc, cls); default: break; } if (sc.CheckToken('(')) { switch (identifier) { case NAME_Min: case NAME_Max: return ParseMinMax(sc, identifier, cls); case NAME_Clamp: return ParseClamp(sc, cls); case NAME_Abs: return ParseAbs(sc, cls); default: args = new FArgumentList; func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true)); try { // There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work. if (func != NULL && identifier != NAME_ACS_NamedExecuteWithResult) { sc.UnGet(); ParseFunctionParameters(sc, cls, *args, func, "", NULL); return new FxVMFunctionCall(func, args, sc); } else if (!sc.CheckToken(')')) { do { args->Push(ParseExpressionM (sc, cls)); } while (sc.CheckToken(',')); sc.MustGetToken(')'); } return new FxFunctionCall(NULL, identifier, args, sc); } catch (...) { delete args; throw; } break; } } else { return new FxIdentifier(identifier, sc); } } else { FString tokname = sc.TokenName(sc.TokenType, sc.String); sc.ScriptError ("Unexpected token %s", tokname.GetChars()); } return NULL; }
static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) { FScriptPosition scpos(sc); if (sc.CheckToken('(')) { FxExpression *data = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return data; } else if (sc.CheckToken(TK_True)) { return new FxConstant(1, scpos); } else if (sc.CheckToken(TK_False)) { return new FxConstant(0, scpos); } else if (sc.CheckToken(TK_IntConst)) { return new FxConstant(sc.Number, scpos); } else if (sc.CheckToken(TK_FloatConst)) { return new FxConstant(sc.Float, scpos); } else if (sc.CheckToken(TK_NameConst)) { return new FxConstant(sc.Name, scpos); } else if (sc.CheckToken(TK_StringConst)) { // String parameters are converted to names. Technically, this should be // done at a higher level, as needed, but since no functions take string // arguments and ACS_NamedExecuteWithResult/CallACS need names, this is // a cheap way to get them working when people use "name" instead of 'name'. return new FxConstant(FName(sc.String), scpos); } else if (sc.CheckToken(TK_Random)) { FRandom *rng; if (sc.CheckToken('[')) { sc.MustGetToken(TK_Identifier); rng = FRandom::StaticFindRNG(sc.String); sc.MustGetToken(']'); } else { rng = &pr_exrandom; } sc.MustGetToken('('); FxExpression *min = ParseExpressionM (sc, cls); sc.MustGetToken(','); FxExpression *max = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return new FxRandom(rng, min, max, sc); } else if (sc.CheckToken(TK_RandomPick) || sc.CheckToken(TK_FRandomPick)) { bool floaty = sc.TokenType == TK_FRandomPick; FRandom *rng; TArray<FxExpression*> list; list.Clear(); int index = 0; if (sc.CheckToken('[')) { sc.MustGetToken(TK_Identifier); rng = FRandom::StaticFindRNG(sc.String); sc.MustGetToken(']'); } else { rng = &pr_exrandom; } sc.MustGetToken('('); for (;;) { FxExpression *expr = ParseExpressionM(sc, cls); list.Push(expr); if (sc.CheckToken(')')) break; sc.MustGetToken(','); } return new FxRandomPick(rng, list, floaty, sc); } else if (sc.CheckToken(TK_FRandom)) { FRandom *rng; if (sc.CheckToken('[')) { sc.MustGetToken(TK_Identifier); rng = FRandom::StaticFindRNG(sc.String); sc.MustGetToken(']'); } else { rng = &pr_exrandom; } sc.MustGetToken('('); FxExpression *min = ParseExpressionM (sc, cls); sc.MustGetToken(','); FxExpression *max = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return new FxFRandom(rng, min, max, sc); } else if (sc.CheckToken(TK_Random2)) { FRandom *rng; if (sc.CheckToken('[')) { sc.MustGetToken(TK_Identifier); rng = FRandom::StaticFindRNG(sc.String); sc.MustGetToken(']'); } else { rng = &pr_exrandom; } sc.MustGetToken('('); FxExpression *mask = NULL; if (!sc.CheckToken(')')) { mask = ParseExpressionM(sc, cls); sc.MustGetToken(')'); } return new FxRandom2(rng, mask, sc); } else if (sc.CheckToken(TK_Abs)) { sc.MustGetToken('('); FxExpression *x = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return new FxAbs(x); } else if (sc.CheckToken(TK_Identifier)) { FName identifier = FName(sc.String); if (sc.CheckToken('(')) { FArgumentList *args = new FArgumentList; PFunction *func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true)); try { if (func != NULL) { sc.UnGet(); ParseFunctionParameters(sc, cls, *args, func, "", NULL); return new FxVMFunctionCall(func, args, sc); } else if (!sc.CheckToken(')')) { do { args->Push(ParseExpressionM (sc, cls)); } while (sc.CheckToken(',')); sc.MustGetToken(')'); } return new FxFunctionCall(NULL, identifier, args, sc); } catch (...) { delete args; throw; } } else { return new FxIdentifier(identifier, sc); } } else { FString tokname = sc.TokenName(sc.TokenType, sc.String); sc.ScriptError ("Unexpected token %s", tokname.GetChars()); } return NULL; }