using arookas.Collections; using arookas.IO.Binary; using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace arookas { class sunSymbolTable : IEnumerable<sunSymbolInfo> { List<sunSymbolInfo> symbols = new List<sunSymbolInfo>(10); public int Count { get { return symbols.Count; } } public int BuiltinCount { get { return symbols.Count(sym => sym.Type == sunSymbolType.Builtin); } } public int FunctionCount { get { return symbols.Count(sym => sym.Type == sunSymbolType.Function); } } public int VariableCount { get { return symbols.Count(sym => sym.Type == sunSymbolType.Variable); } } public IEnumerable<sunCallableSymbolInfo> Callables { get { return symbols.OfType<sunCallableSymbolInfo>(); } } public IEnumerable<sunBuiltinInfo> Builtins { get { return symbols.Where(sym => sym.Type == sunSymbolType.Builtin).Cast<sunBuiltinInfo>(); } } public IEnumerable<sunFunctionInfo> Functions { get { return symbols.Where(sym => sym.Type == sunSymbolType.Function).Cast<sunFunctionInfo>(); } } public IEnumerable<sunVariableInfo> Variables { get { return symbols.Where(sym => sym.Type == sunSymbolType.Variable).Cast<sunVariableInfo>(); } } public void Add(sunSymbolInfo symbol) { symbols.Add(symbol); } public void Clear() { symbols.Clear(); } public void Write(aBinaryWriter writer) { int ofs = 0; foreach (var sym in this) { writer.WriteS32((int)sym.Type); writer.WriteS32(ofs); writer.Write32(sym.Data); // runtime fields writer.WriteS32(0); writer.WriteS32(0); ofs += sym.Name.Length + 1; // include null terminator } foreach (var sym in this) { writer.WriteString(sym.Name, aBinaryStringFormat.NullTerminated); } } public IEnumerator<sunSymbolInfo> GetEnumerator() { return symbols.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } abstract class sunSymbolInfo { public string Name { get; private set; } // symbol table public abstract sunSymbolType Type { get; } public abstract uint Data { get; } protected sunSymbolInfo(string name) { Name = name; } } abstract class sunCallableSymbolInfo : sunSymbolInfo { public sunParameterInfo Parameters { get; private set; } protected List<sunPoint> CallSites { get; private set; } public bool HasCallSites { get { return CallSites.Count > 0; } } protected sunCallableSymbolInfo(string name, sunParameterInfo parameterInfo) : base(name) { Parameters = parameterInfo; CallSites = new List<sunPoint>(10); } public abstract void OpenCallSite(sunContext context, int argumentCount); public abstract void CloseCallSites(sunContext context); public abstract void Compile(sunContext context); } class sunBuiltinInfo : sunCallableSymbolInfo { public int Index { get; private set; } // symbol table public override sunSymbolType Type { get { return sunSymbolType.Builtin; } } public override uint Data { get { return (uint)Index; } } public sunBuiltinInfo(string name, sunParameterInfo parameters, int index) : base(name, parameters) { Index = index; } public override void Compile(sunContext context) { throw new InvalidOperationException("Cannot compile builtins."); } public override void OpenCallSite(sunContext context, int argumentCount) { context.Text.CallBuiltin(Index, argumentCount); } public override void CloseCallSites(sunContext context) { // do nothing } } class sunFunctionInfo : sunCallableSymbolInfo { sunNode Body { get; set; } public uint Offset { get; private set; } // symbol table public override sunSymbolType Type { get { return sunSymbolType.Function; } } public override uint Data { get { return (uint)Offset; } } public sunFunctionInfo(string name, sunParameterInfo parameters, sunNode body) : base(name, parameters) { Body = body; } public override void Compile(sunContext context) { Offset = context.Text.Offset; context.Scopes.Push(); foreach (var parameter in Parameters) { context.DeclareParameter(parameter); } context.Text.StoreDisplay(1); Body.Compile(context); context.Text.ReturnVoid(); context.Scopes.Pop(); } public override void OpenCallSite(sunContext context, int argumentCount) { var point = context.Text.CallFunction(argumentCount); CallSites.Add(point); } public override void CloseCallSites(sunContext context) { foreach (var callSite in CallSites) { context.Text.ClosePoint(callSite, Offset); } } } class sunParameterInfo : IEnumerable<string> { string[] Parameters { get; set; } public int Minimum { get { return Parameters.Length; } } public bool IsVariadic { get; private set; } public sunParameterInfo(IEnumerable<sunIdentifier> parameters, bool variadic) { // validate parameter names var duplicate = parameters.FirstOrDefault(a => parameters.Count(b => a.Value == b.Value) > 1); if (duplicate != null) { throw new sunRedeclaredParameterException(duplicate); } Parameters = parameters.Select(i => i.Value).ToArray(); IsVariadic = variadic; } public sunParameterInfo(IEnumerable<string> parameters, bool variadic) { // validate parameter names Parameters = parameters.ToArray(); IsVariadic = variadic; } public bool ValidateArgumentCount(int count) { return IsVariadic ? count >= Minimum : count == Minimum; } public IEnumerator<string> GetEnumerator() { return Parameters.GetArrayEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } class sunVariableInfo : sunSymbolInfo { public int Display { get; private set; } public int Index { get; private set; } // symbol table public override sunSymbolType Type { get { return sunSymbolType.Variable; } } public override uint Data { get { return (uint)Index; } } public sunVariableInfo(string name, int display, int index) : base(name) { Display = display; Index = index; } } enum sunSymbolType { Builtin, Function, Variable, } }