public static Formula parseFormula(string text, ParsedThing parsedThing) { return new FormulaParser(parsedThing).parse(text); }
public FormulaParser(ParsedThing parsedThing) { this.parsedThing = parsedThing; }
private static GurpsProperty createParsedThing(ParsedThing parsedThing) { if (parsedThing.subPropertyName != null) throw parsedThing.createError("No '.' allowed in names"); switch (parsedThing.declarationOperator) { case ":": if (skillFormulaRegex.IsMatch(parsedThing.formula)) { SkillDifficulty difficulty = AbstractSkill.difficultyFromChar(parsedThing.formula[parsedThing.formula.Length - 1]); Formula formula = FormulaParser.parseFormula(parsedThing.formula.Remove(parsedThing.formula.Length - 1), parsedThing); return new Skill(parsedThing, difficulty, formula); } else { Formula costFormula = FormulaParser.parseFormula(parsedThing.formula, parsedThing); if (costFormula.usedNames().Contains("level")) return new IntAdvantage(parsedThing, costFormula); else return new BooleanAdvantage(parsedThing, costFormula); } case ":=": { SkillDifficulty difficulty = SkillDifficulty.Unspecified; string formulaText = parsedThing.formula; if (skillFormulaRegex.IsMatch(parsedThing.formula)) { difficulty = AbstractSkill.difficultyFromChar(parsedThing.formula[parsedThing.formula.Length - 1]); formulaText = parsedThing.formula.Remove(parsedThing.formula.Length - 1); } Formula formula = FormulaParser.parseFormula(formulaText, parsedThing); if (!(formula is Formula.Identifier)) throw parsedThing.createError("expected name of skill. got '" + formulaText + "'"); return new InheritedSkill(parsedThing, difficulty, ((Formula.Identifier)formula).token); } case "=": { Formula formula = FormulaParser.parseFormula(parsedThing.formula, parsedThing); return new AttributeFunction(parsedThing, formula); } default: throw parsedThing.createError("expected ':', '=', or ':='. Got '" + parsedThing.declarationOperator + "'"); } }
private static IEnumerable<ParsedThing> parseFile(string path) { string[] lines = File.ReadAllLines(path); for (int i = 0; i < lines.Length; i++) { string line; if (isLineBlank(line = lines[i].Trim())) continue; Action throwParseError = delegate() { throw new GurpenatorException("syntax problem (" + path + ":" + (i + 1) + ")"); }; Match match = null; // hack for local recursion (for DRY) Func<ParsedThing> parseThing = null; parseThing = delegate() { string name = match.Groups[1].Value.Trim(); string subPropertyName = match.Groups[2].Success ? match.Groups[2].Value.Trim() : null; string declarationOperator = match.Groups[3].Value; string formula = match.Groups[4].Value.Trim(); string comment = match.Groups[5].Success ? match.Groups[5].Value.Trim() : null; ParsedThing thing = new ParsedThing(name, subPropertyName, declarationOperator, formula, comment, path, i + 1); if (reservedWords.Contains(name)) throw thing.createError("name '" + name + "' is reserved"); bool hasOpenBrace = match.Groups[6].Success; if (!hasOpenBrace) return thing; i++; int firstLineIndex = i; for (; i < lines.Length; i++) { if (isLineBlank(line = lines[i].Trim())) continue; if (line == "}") return thing; if (i == firstLineIndex && (match = commentRegex.Match(line)).Success) { // the first line can be the comment if (thing.comment != null) throwParseError(); // two comments? thing.comment = match.Groups[1].Value; continue; } if ((match = thingStartLineRegex.Match(line)).Success) { thing.subThings.Add(parseThing()); continue; } throwParseError(); } throw thing.createError("syntax problem. '{' missing '}'"); }; if ((match = thingStartLineRegex.Match(line)).Success) { yield return parseThing(); continue; } throwParseError(); } }
public PercentToken(ParsedThing parseThing, decimal value) : base(parseThing) { this.value = value; }
public InheritedSkill(ParsedThing parsedThing, SkillDifficulty difficultyOverride, IdentifierToken parentSkillToken) : base(parsedThing) { this.difficultyOverride = difficultyOverride; this.parentSkillToken = parentSkillToken; }
protected Effect(GurpsProperty owner, string traitName, Formula formula, ParsedThing parsedThing) { this.owner = owner; this.traitName = traitName; this.formula = formula; this.parsedThing = parsedThing; }
public SymbolToken(ParsedThing parseThing, string text) : base(parseThing) { this.text = text; }
public BooleanAdvantage(ParsedThing parsedThing, Formula costFormula) : base(parsedThing, costFormula) { formattingFunction = intToBoolFormattingFunction; }
public CostModifier(GurpsProperty owner, string traitName, Formula formula, ParsedThing parsedThing) : base(owner, traitName, formula, parsedThing) { }
public Skill(ParsedThing parsedThing, SkillDifficulty difficulty, Formula formula) : base(parsedThing) { this.difficulty = difficulty; this.formula = formula; }
public AttributeFunction(ParsedThing parsedThing, Formula formula) : base(parsedThing) { this.formula = formula; }
public IntAdvantage(ParsedThing parsedThing, Formula costFormula) : base(parsedThing, costFormula) { }
public Token(ParsedThing parseThing) { this.parseThing = parseThing; }
protected AbstractSkill(ParsedThing parsedThing) : base(parsedThing) { }
public IdentifierToken(ParsedThing parseThing, string text) : base(parseThing) { this.text = text; }
public Advantage(ParsedThing parsedThing, Formula costFormula) : base(parsedThing) { this.costFormula = costFormula; }
public IntToken(ParsedThing parseThing, int value) : base(parseThing) { this.value = value; }
private static GurpsProperty interpretParsedThing(ParsedThing parsedThing) { GurpsProperty property = createParsedThing(parsedThing); foreach (ParsedThing subThing in parsedThing.subThings) { if (new string[] { "category", "default", "requires" }.Contains(subThing.name)) { if (subThing.subPropertyName != null) throw subThing.createError("property '" + subThing.name + "' has no subproperty '" + subThing.subPropertyName + "'"); Formula formula = FormulaParser.parseFormula(subThing.formula, subThing); switch (subThing.name) { case "category": if (!(formula is Formula.BooleanLiteral)) throw subThing.createError("categry can only be 'true' or 'false'"); if (!(property is AbstractSkill)) throw subThing.createError("only skills can be categories"); ((AbstractSkill)property).category = ((Formula.BooleanLiteral)formula).value.value; continue; case "default": case "requires": // TODO continue; } throw null; } switch (subThing.declarationOperator) { case "+=": case "-=": { string traitName = subThing.name; Formula formula = FormulaParser.parseFormula(subThing.formula, subThing); if (subThing.subPropertyName == null) { if (subThing.declarationOperator == "-=") { // negate the formula formula = new Formula.UnaryPrefix(new SymbolToken(subThing, "-"), formula); } property.effects.Add(new TraitModifier(property, traitName, formula, subThing)); } else if (subThing.subPropertyName == "cost") property.effects.Add(new CostModifier(property, traitName, formula, subThing)); else throw subThing.createError("can't modify the '" + subThing.subPropertyName + "' of another trait"); if (subThing.subThings.Count > 0) throw subThing.subThings[0].createError("Subitems not allowed here"); continue; } case ":": if (subThing.subPropertyName != null) throw subThing.createError("No '.' allowed in names"); // TODO continue; } throw subThing.createError("illegal operator '" + subThing.declarationOperator + "' for property"); } return property; }
public BooleanToken(ParsedThing parseThing, bool value) : base(parseThing) { this.value = value; }
protected GurpsProperty(ParsedThing parsedThing) { this.parsedThing = parsedThing; }