/// <summary> /// <see cref="KecaknoahSource"/>から指定の<see cref="Stream"/>にバイトコードを出力します。 /// </summary> /// <param name="source">対象の<see cref="KecaknoahSource"/></param> /// <param name="output">出力先</param> public static void Save(KecaknoahSource source, Stream output) { using (var writer = new BinaryWriter(output, stringEncoding, true)) { writer.Write(magicNumber); writer.Write(BytecodeVersion); writer.Write(source.Uses.Count + source.Classes.Count + source.TopLevelMethods.Count); foreach (var x in source.Uses) { writer.Write((byte)TopLevelBlockType.Use); writer.Write(x); } foreach (var x in source.Classes) { writer.Write((byte)TopLevelBlockType.Class); WriteClass(x, writer); } foreach (var x in source.TopLevelMethods) { writer.Write((byte)TopLevelBlockType.TopLevelMethod); WriteMethod(x, writer); } } }
/// <summary> /// 1つのソースコード全体からなる<see cref="KecaknoahAst"/>をプリコンパイルします。 /// </summary> /// <param name="ast">対象の<see cref="KecaknoahAst"/></param> /// <returns>プリコンパイル結果</returns> public KecaknoahSource PrecompileAll(KecaknoahAst ast) { var result = new KecaknoahSource(); current = result; foreach (var i in ast.RootNode.Children) { if (i is KecaknoahClassAstNode) { result.classes.Add(PrecompileClass(i as KecaknoahClassAstNode)); } else if (i is KecaknoahFunctionAstNode) { result.methods.Add(PrecompileFunction(i as KecaknoahFunctionAstNode)); } else if (i is KecaknoahUseAstNode) { result.uses.Add((i as KecaknoahUseAstNode).Target); } else { throw new InvalidOperationException("トップレベルにはクラスとメソッドとuse文以外おけません"); } } current = null; return result; }
/// <summary> /// プリコンパイルしたソースコードを登録します。 /// </summary> /// <param name="src">登録する<see cref="KecaknoahSource"/></param> public void RegisterSource(KecaknoahSource src) { foreach (var c in src.Classes) { classes.Add(c); classReferences.Add(KecaknoahReference.CreateRightReference(new KecaknoahScriptClassObject(c))); } foreach (var m in src.TopLevelMethods) { topMethods.Add(m); methodReferences.Add(KecaknoahReference.CreateRightReference(new KecaknoahScriptFunction(KecaknoahNil.Instance, m))); } }
static IList<string> AssembleSource(KecaknoahSource info) { var result = new List<string>(); foreach (var i in info.Classes) { result.AddRange(AssembleClass(i as KecaknoahScriptClassInfo)); result.Add(""); } foreach (var i in info.TopLevelMethods) { result.AddRange(AssembleFunction(i as KecaknoahScriptMethodInfo)); result.Add(""); } return result; }
/// <summary> /// 1つのソースコード全体からなる<see cref="KecaknoahAst"/>をプリコンパイルします。 /// </summary> /// <param name="ast">対象の<see cref="KecaknoahAst"/></param> /// <returns>プリコンパイル結果</returns> public KecaknoahSource PrecompileAll(KecaknoahAst ast) { var result = new KecaknoahSource(); current = result; foreach (var i in ast.RootNode.Children) { if (i is KecaknoahClassAstNode) { result.classes.Add(PrecompileClass(i as KecaknoahClassAstNode)); } else if (i is KecaknoahFunctionAstNode) { result.methods.Add(PrecompileFunction(i as KecaknoahFunctionAstNode)); } else { throw new InvalidOperationException("トップレベルにはクラスとメソッド以外おけません"); } } current = null; return(result); }
/// <summary> /// バイトコードを読み込み、<see cref="KecaknoahSource"/>に変換します。 /// </summary> /// <param name="input"></param> /// <returns></returns> public static KecaknoahSource Load(Stream input) { using (var reader = new BinaryReader(input, stringEncoding, true)) { if (!reader.ReadBytes(magicNumber.Length).SequenceEqual(magicNumber)) throw new InvalidDataException("合言葉は「KC」"); var version = reader.ReadUInt16(); if (version > BytecodeVersion) throw new InvalidDataException($"Kecaknoah Bytecode v{version} には対応していません。"); var result = new KecaknoahSource(); var count = reader.ReadInt32(); for (var i = 0; i < count; i++) { switch ((TopLevelBlockType)reader.ReadByte()) { case TopLevelBlockType.Use: result.uses.Add(reader.ReadString()); break; case TopLevelBlockType.Class: result.classes.Add(ReadClass(reader)); break; case TopLevelBlockType.TopLevelMethod: result.methods.Add(ReadMethod(reader)); break; default: throw new InvalidDataException("変なデータが出ーた!wwww"); } } return result; } }
private void ProcessUseDirective(KecaknoahSource src) { var cur = Directory.GetCurrentDirectory(); var asm = Path.GetDirectoryName(typeof(KecaknoahModule).Assembly.Location); var lex = new KecaknoahLexer(); var par = new KecaknoahParser(); var prc = new KecaknoahPrecompiler(); foreach (var text in src.Uses) { var arg = text.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); switch (arg[0]) { case "import": var it = Path.Combine(cur, arg[1]); Directory.SetCurrentDirectory(Path.GetDirectoryName(it)); var s = prc.PrecompileAll(par.Parse(lex.AnalyzeFromFile(it))); RegisterSource(s); Directory.SetCurrentDirectory(cur); break; case "stdlib": var lt = Path.Combine(asm, "lib"); Directory.SetCurrentDirectory(Path.GetDirectoryName(lt)); var s2 = prc.PrecompileAll(par.Parse(lex.AnalyzeFromFile(lt))); RegisterSource(s2); Directory.SetCurrentDirectory(cur); break; } } }