<commit_before>﻿using System.Linq;

namespace Crayon.ParseTree
{
	internal class DotStep : Expression
	{
		public Expression Root { get; set; }
		public Token DotToken { get; private set; }
		public Token StepToken { get; private set; }

		public DotStep(Expression root, Token dotToken, Token stepToken)
			: base(root.FirstToken)
		{
			this.Root = root;
			this.DotToken = dotToken;
			this.StepToken = stepToken;
		}

		public override Expression Resolve(Parser parser)
		{
			this.Root = this.Root.Resolve(parser);

			string step = this.StepToken.Value;
			Variable variable = this.Root as Variable;
			if (variable != null)
			{
				string varName = variable.Name;

				EnumDefinition enumDef = parser.GetEnumDefinition(varName);
				if (enumDef != null)
				{
					if (enumDef.IntValue.ContainsKey(step))
					{
						return new IntegerConstant(this.FirstToken, enumDef.IntValue[step]);
					}
					throw new ParserException(this.StepToken, "The enum '" + variable.Name + "' does not contain a definition for '" + step + "'");
				}

				if (parser.IsTranslateMode && varName.Contains('$'))
				{
					string[] parts = varName.Split('$');
					if (parts.Length == 2 && parts[0].Length > 0 && parts[1].Length > 0)
					{
						// struct casting
						string structName = parts[0];
						string realVarName = parts[1];
						StructDefinition structDef = parser.GetStructDefinition(structName);
						if (!structDef.IndexByField.ContainsKey(step))
						{
							throw new ParserException(this.StepToken, "The struct '" + structDef.Name.Value + "' does not contain a field called '" + step + "'");
						}
						return new DotStepStruct(this.FirstToken, structDef, this);
					}
				}
			}

			return this;
		}
	}
}<commit_msg>Add a few compile time features to calling a field on a string literal... - Crash at COMPILE TIME if you call .join and explain that the string joiner is done by calling .join on a list with a string as an argument. - Crash at COMPILE TIME when you call .size and redirect the user to .length - Swap out string.length with the actual length when the string is an inline constant.<commit_after>﻿using System.Linq;

namespace Crayon.ParseTree
{
	internal class DotStep : Expression
	{
		public Expression Root { get; set; }
		public Token DotToken { get; private set; }
		public Token StepToken { get; private set; }

		public DotStep(Expression root, Token dotToken, Token stepToken)
			: base(root.FirstToken)
		{
			this.Root = root;
			this.DotToken = dotToken;
			this.StepToken = stepToken;
		}

		public override Expression Resolve(Parser parser)
		{
			this.Root = this.Root.Resolve(parser);

			string step = this.StepToken.Value;
			Variable variable = this.Root as Variable;
			if (variable != null)
			{
				string varName = variable.Name;

				EnumDefinition enumDef = parser.GetEnumDefinition(varName);
				if (enumDef != null)
				{
					if (enumDef.IntValue.ContainsKey(step))
					{
						return new IntegerConstant(this.FirstToken, enumDef.IntValue[step]);
					}
					throw new ParserException(this.StepToken, "The enum '" + variable.Name + "' does not contain a definition for '" + step + "'");
				}

				if (parser.IsTranslateMode && varName.Contains('$'))
				{
					string[] parts = varName.Split('$');
					if (parts.Length == 2 && parts[0].Length > 0 && parts[1].Length > 0)
					{
						// struct casting
						string structName = parts[0];
						string realVarName = parts[1];
						StructDefinition structDef = parser.GetStructDefinition(structName);
						if (!structDef.IndexByField.ContainsKey(step))
						{
							throw new ParserException(this.StepToken, "The struct '" + structDef.Name.Value + "' does not contain a field called '" + step + "'");
						}
						return new DotStepStruct(this.FirstToken, structDef, this);
					}
				}
			}

			if (this.Root is StringConstant)
			{
				if (step == "join")
				{
					throw new ParserException(this.StepToken,
						"There is no join method on strings, you silly Python user. Did you mean to do list.join(string) instead?");
				}
				else if (step == "size")
				{
					throw new ParserException(this.StepToken, "String size is indicated by string.length.");
				}
				else if (step == "length")
				{
					int length = ((StringConstant)this.Root).Value.Length;
					return new IntegerConstant(this.FirstToken, length);
				}
			}

			return this;
		}
	}
}
{'fraction_non_alphanumeric': 0.11439029970258523, 'fraction_numerical': 0.003202928391672386, 'mean_word_length': 3.044403330249769, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6418902', 'n_tokens_mistral': 1643, 'n_tokens_neox': 1288, 'n_words': 383}