Example #1
0
 /// <summary>
 /// 构建抽象语法树
 /// </summary>
 /// <param name="tokens">Token序列内容</param>
 /// <param name="identifier">源文件ID</param>
 /// <returns></returns>
 public static ScopeExpression Parse(IEnumerable <BasicToken> tokens, CodeIdentifier identifier)
 {
     return(new Parser(tokens, identifier).Parse());
 }
Example #2
0
 private Parser(IEnumerable <BasicToken> tokens, CodeIdentifier identifier)
 {
     Tokens     = new SourceTokens(tokens);
     Identifier = identifier;
 }
 /// <summary>
 /// 创建一个编译错误
 /// </summary>
 /// <param name="identifier">目标文件</param>
 /// <param name="position">错误位置</param>
 /// <param name="message">错误信息</param>
 public CompileException(CodeIdentifier identifier, SourcePosition position, string message)
     : base($"{message} (at {identifier.Id}[{identifier.Hash}]:{position.Line + 1}:{position.Column + 1})")
 {
 }
Example #4
0
        /// <summary>
        /// 编译文件
        /// </summary>
        /// <param name="path">脚本ID</param>
        /// <param name="forceCompile">是否强制重新编译</param>
        /// <returns>发生变化的文件列表</returns>
        public static IEnumerable <string> CompileAsset(string path, bool forceCompile = false)
        {
            if (!Application.isEditor)
            {
                throw new NotSupportedException($"Cannot compile {path}: static file compiler can only run in editor mode");
            }
            if (!path.EndsWith(".vns"))
            {
                throw new NotSupportedException($"Cannot compile {path}: file name extension must be .vns");
            }
            var option = ScriptInformation.CreateInformationFromAsset(path);

            if (option == null)
            {
                throw new NullReferenceException($"Cannot compile {path}: target outside of source folder or target is not acceptable script/binary");
            }
            var changedFiles = new List <string>();
            var source       = File.ReadAllText(path, Encoding.UTF8).UnifyLineBreak();

            if (!option.Hash.HasValue)
            {
                option.Hash = Hasher.Crc32(Encoding.UTF8.GetBytes(source));
            }
            var identifier = new CodeIdentifier {
                Id = option.Id, Hash = option.Hash.Value
            };

            // 编译文件
            if (!forceCompile)
            {
                if (option.RecordedHash.HasValue && option.RecordedHash.Value == identifier.Hash)
                {
                    return(new string[] { }); // 如果源代码内容没有变化则直接跳过编译
                }
            }
            var(content, defaultTranslation) = CompileCode(source, identifier);
            var binaryFile = option.BinaryAssetPath();

            File.WriteAllBytes(binaryFile, content);
            option.RecordedHash = option.Hash = identifier.Hash;
            changedFiles.Add(binaryFile);
            // 处理其他翻译
            foreach (var(language, _) in option.Translations)
            {
                var languageFile = option.LanguageAssetPath(language);
                if (File.Exists(languageFile))
                {
                    var existedTranslation = new ScriptTranslation(File.ReadAllText(languageFile));
                    if (!existedTranslation.MergeWith(defaultTranslation))
                    {
                        continue;
                    }
                    existedTranslation.SaveToAsset(languageFile);
                    changedFiles.Add(languageFile);
                }
                else
                {
                    // 如果翻译不存在,以默认翻译为蓝本新建翻译文件
                    defaultTranslation.SaveToAsset(languageFile);
                    changedFiles.Add(languageFile);
                }
            }
            CompileConfiguration.Save();
            return(changedFiles);
        }
Example #5
0
 /// <summary>
 /// 编译源代码
 /// </summary>
 /// <param name="source">源代码文本</param>
 /// <param name="identifier">源代码脚本ID</param>
 /// <returns></returns>
 public static (byte[] Content, ScriptTranslation DefaultTranslation) CompileCode(string source, CodeIdentifier identifier)
 {
     return(ByteCodeGenerator.Generate(Parser.Parse(Lexer.Lex(source, identifier), identifier), identifier));
 }
Example #6
0
        /// <summary>
        /// 生成字节码
        /// </summary>
        /// <param name="root">根表达式</param>
        /// <param name="identifier">源文件ID</param>
        /// <returns></returns>
        public static (byte[] Content, ScriptTranslation DefaultTranslations) Generate(ScopeExpression root, CodeIdentifier identifier)
        {
            var context = new ByteCodeGeneratorContext();

            // 生成主程序段
            Generate(context, root);
            // 生成各种段
            var(code, labels, strings, positions, translations) = context.File.CreateSegments();
            context.File.Close();
            // 准备目标文件
            var targetFile = new ByteCodeWriter();

            // 写入文件标志 ("VisualNovelScript Version 1, assembly format"的CRC32)
            targetFile.DirectWrite(0x963EFE4A);
            // 写入源文件哈希用于跳过重复编译
            targetFile.DirectWrite(identifier.Hash);
            // 写入各种段
            targetFile.DirectWrite(translations.ToByteArray());
            targetFile.DirectWrite(strings);
            targetFile.DirectWrite(labels);
            targetFile.DirectWrite(positions);
            targetFile.DirectWrite(code);
            return(targetFile.CreateMainSegment(), translations);
        }