using System;
using System.Collections.Immutable;
using System.Linq;
using ABT;
using static AST.SemanticAnalysis;
namespace AST {
public interface ISyntaxTreeNode : IStoredLineInfo { }
///
/// A translation unit consists of a list of external declarations - functions and objects.
///
public sealed class TranslnUnit : ISyntaxTreeNode {
public int Line { get; private set; }
public int Column { get; private set; }
public void Copy(ILineInfo info)
{
Line = info.Line;
Column = info.Column;
}
private TranslnUnit(ImmutableList declns) {
this.Declns = declns;
}
public static TranslnUnit Create(ImmutableList externDeclns) =>
new TranslnUnit(externDeclns);
[SemantMethod]
public ISemantReturn GetTranslnUnit() {
var env = new Env();
var externDeclns = this.Declns.Aggregate(ImmutableList>.Empty, (acc, externDecln) => acc.AddRange(Semant(externDecln.GetExternDecln, ref env))
);
return SemantReturn.Create(env, new ABT.TranslnUnit(externDeclns.ToList()));
}
public ImmutableList Declns { get; }
}
public interface IExternDecln : ISyntaxTreeNode {
[SemantMethod]
ISemantReturn>> GetExternDecln(Env env);
}
///
/// A function definition gives the implementation.
///
public sealed class FuncDef : IExternDecln {
public int Line { get; private set; }
public int Column { get; private set; }
public void Copy(ILineInfo info)
{
Line = info.Line;
Column = info.Column;
}
public FuncDef(DeclnSpecs specs, Declr declr, CompoundStmt stmt) {
this.Specs = specs;
this.Declr = declr;
this.Stmt = stmt;
}
public static FuncDef Create(Option declnSpecs, Declr declr, Stmt body) =>
new FuncDef(declnSpecs.IsSome ? declnSpecs.Value : DeclnSpecs.Empty, declr, body as CompoundStmt);
public DeclnSpecs Specs { get; }
public Declr Declr { get; }
public CompoundStmt Stmt { get; }
[SemantMethod]
public ISemantReturn>> GetExternDecln(Env env) {
var storageClass = this.Specs.GetStorageClass();
var baseType = Semant(this.Specs.GetExprType, ref env);
var name = this.Declr.Name;
var type = Semant(this.Declr.DecorateType, baseType, ref env);
var funcType = type as FunctionType;
if (funcType == null) {
throw new InvalidOperationException("Expected a function Type.").Attach(this);
}
switch (storageClass) {
case StorageClass.AUTO:
case StorageClass.EXTERN:
case StorageClass.STATIC:
env = env.PushEntry(Env.EntryKind.GLOBAL, name, type);
break;
case StorageClass.TYPEDEF:
default:
throw new InvalidOperationException("Invalid storage class specifier for function definition.").Attach(this);
}
env = env.InScope();
env = env.SetCurrentFunction(funcType);
var stmt = SemantStmt(this.Stmt.GetStmt, ref env);
env = env.OutScope();
ABT.IExternDecln funcDef = new ABT.FuncDef(name, storageClass, funcType, stmt);
funcDef.Copy(this);
return SemantReturn.Create(env, ImmutableList.Create(Tuple.Create(env, funcDef)));
}
}
}