diff --git a/src/prettyPrinter/PrettyPrinter.cj b/src/prettyPrinter/PrettyPrinter.cj index 001c2ef..c334914 100644 --- a/src/prettyPrinter/PrettyPrinter.cj +++ b/src/prettyPrinter/PrettyPrinter.cj @@ -1,6 +1,7 @@ package cjcj.prettyPrinter public class PrettyPrinter { + public PrettyPrinter(let tabSize!: Int64 = 4) {} private var indentation: Int64 = 0 private let builder: StringBuilder = StringBuilder() @@ -13,13 +14,10 @@ public class PrettyPrinter { } public func append(val: String): Unit { - val.runes().forEach( - { - r => - builder.append(r) - if (r == r"\n") { - builder.append(StringBuilder(r' ', 4 * indentation)) - } + val.runes().forEach({ + r => builder.append(r) + if (r == r"\n") { + builder.append(StringBuilder(r' ', tabSize * indentation)) } ) } diff --git a/src/prettyPrinter/YamlPrinter.cj b/src/prettyPrinter/YamlPrinter.cj new file mode 100644 index 0000000..40f823b --- /dev/null +++ b/src/prettyPrinter/YamlPrinter.cj @@ -0,0 +1,110 @@ +package cjcj.prettyPrinter + +import cjcj.scanner.{Token, TokenKind} +import std.ast.Position + +public interface YamlPrintable { + func yamlPrint(printer: YamlPrinter): Unit +} + +public class YamlPrinter { + private var indentation: Int64 = 0 + private let printer: PrettyPrinter = PrettyPrinter(tabSize: 2) + private var atObjectStart: Bool = true + private var atListItemStart: Bool = false + + private func printlnIfNeeded(): Unit { + if (atObjectStart) { + atObjectStart = false + if (atListItemStart) { + atListItemStart = false + printer.indent() + } + } else { + printer.append("\n") + } + } + + public func printObject(key: String, obj: YamlPrintable): Unit { + printlnIfNeeded() + printer.append(key + ":") + printer.indent() + printer.append("\n") + atObjectStart = true + obj.yamlPrint(this) + atObjectStart = false + printer.unindent() + } + + public func printOptionalObject(key: String, obj: ?T): Unit where T <: YamlPrintable { + if (let Some(o) <- obj) { + printObject(key, o) + } else { + printlnIfNeeded() + printer.append(key + ": null") + } + } + + public func printList(key: String, objs: Iterable): Unit where T <: YamlPrintable { + printlnIfNeeded() + if (objs.iterator().isEmpty()) { + printer.append(key + ": []") + return + } + printer.append(key + ":") + objs.iterator().forEach( + { + o => + printer.append("\n- ") + atObjectStart = true + atListItemStart = true + o.yamlPrint(this) + if (atListItemStart) { + printer.append("{}") + atListItemStart = false + } else { + printer.unindent() + } + atObjectStart = false + } + ) + } + + public func print(key: String, token: Token): Unit { + print(key, token.value) + printPosition(token.pos) + } + + public func print(key: String, value: ToString, enforceQuoting!: Bool = false): Unit { + let valueString = value.toString() + let formattedValue = if (!enforceQuoting && valueString.runes().all({r => r.isAsciiNumberOrLetter()})) { + valueString + } else if (valueString.contains("\n") || valueString.contains("\t") || valueString.contains("'")) { + '\"${valueString.replace("\\", "\\\\").replace("\n", "\\n").replace("\t", "\\t").replace('"', '\\"')}\"' + } else { + "'${valueString}'" + } + printRaw(key, formattedValue) + } + + public func printLiteral(key: String, literal: Token): Unit { + match (literal.kind) { + case TokenKind.STRING_LITERAL => print(key, literal.value, enforceQuoting: true) + case _ => print(key, literal.value) + } + printPosition(literal.pos) + } + + private func printRaw(key: String, rawValue: String): Unit { + printlnIfNeeded() + printer.append("${key}: ${rawValue}") + } + + private func printPosition(pos: Position): Unit { + printer.append(" # Position: ${pos.line}:${pos.column}") + } + + public func toString(): String { + printer.toString() + } +} diff --git a/src/visitor/Decls.cj b/src/visitor/Decls.cj index ddce7df..b7d1b47 100644 --- a/src/visitor/Decls.cj +++ b/src/visitor/Decls.cj @@ -1,6 +1,6 @@ package cjcj.visitor -import cjcj.prettyPrinter.PrettyPrinter +import cjcj.prettyPrinter.{PrettyPrinter, YamlPrinter} import cjcj.scanner.Token import cjcj.scanner.TokenKind import std.collection.ArrayList @@ -87,6 +87,16 @@ public abstract class Decl <: Node & Equatable { } } + public open override func yamlPrint(printer: YamlPrinter): Unit { + if (keyword.kind != TokenKind.ILLEGAL) { + printer.print("keyword", keyword) + } + if (keyword.kind != TokenKind.ILLEGAL) { + printer.print("identifier", identifier) + } + printer.printOptionalObject("declType", declType) + } + public override operator func ==(other: Decl) { id == other.id } @@ -140,6 +150,12 @@ public open class VarDecl <: Decl { ini.prettyPrint(printer) } } + + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "VarDecl") + super.yamlPrint(printer) + printer.printOptionalObject("initializer", initializer) + } } public open class MainDecl <: Decl { @@ -177,6 +193,13 @@ public open class MainDecl <: Decl { block_.prettyPrint(printer) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "MainDecl") + super.yamlPrint(printer) + printer.printOptionalObject("param", param) + printer.printObject("block", block) + } + public mut prop block: Block { get() { block_ @@ -222,6 +245,13 @@ public class FuncParam <: Decl { paramType.prettyPrint(printer) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "FuncParam") + super.yamlPrint(printer) + printer.print("name", name) + printer.printObject("paramType", paramType) + } + public mut prop paramType: TypeNode { get() { paramType_ @@ -287,6 +317,13 @@ public open class FuncDecl <: Decl { } } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "FuncDecl") + super.yamlPrint(printer) + printer.printList("params", params) + printer.printOptionalObject("block", block) + } + public mut prop block: ?Block { get() { block_ @@ -331,6 +368,13 @@ public open class ClassDecl <: Decl { body.prettyPrint(printer) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "ClassDecl") + super.yamlPrint(printer) + printer.printList("superTypes", superTypes) + printer.printObject("body", body) + } + public open override func traverse(v: Visitor): R { v.visit(this) } @@ -374,6 +418,13 @@ public open class InterfaceDecl <: Decl { body.prettyPrint(printer) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "InterfaceDecl") + super.yamlPrint(printer) + printer.printList("superTypes", superTypes) + printer.printObject("body", body) + } + public open override func traverse(v: Visitor): R { v.visit(this) } diff --git a/src/visitor/Exprs.cj b/src/visitor/Exprs.cj index 99d1b3e..f535b72 100644 --- a/src/visitor/Exprs.cj +++ b/src/visitor/Exprs.cj @@ -1,6 +1,6 @@ package cjcj.visitor -import cjcj.prettyPrinter.PrettyPrinter +import cjcj.prettyPrinter.{PrettyPrinter, YamlPrinter} import cjcj.scanner.Token import cjcj.scanner.TokenKind import std.collection.ArrayList @@ -19,6 +19,13 @@ public open class Expr <: Node { } public open override func prettyPrint(_: PrettyPrinter): Unit {} + + public open func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "Expr") + let valuePrinter = PrettyPrinter() + prettyPrint(valuePrinter) + printer.print("value", '"' + valuePrinter.toString() + '"') + } } public class BinaryExpr <: Expr { @@ -47,6 +54,13 @@ public class BinaryExpr <: Expr { right.prettyPrint(printer) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "BinaryExpr") + printer.printObject("left", left) + printer.print("oper", oper) + printer.printObject("right", right) + } + public mut prop left: Node { get() { left_ @@ -97,6 +111,11 @@ public class ParenExpr <: Expr { printer.append(")") } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "ParenExpr") + printer.printObject("parenthesizedExpr", parenthesizedExpr) + } + public mut prop parenthesizedExpr: Expr { get() { parenthesizedExpr_ @@ -130,6 +149,12 @@ public class LitConstExpr <: Expr { } } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "LitConstExpr") + printer.print("kind", literal.kind) + printer.printLiteral("literal", literal) + } + public mut prop literal: Token { get() { literal_ @@ -163,6 +188,12 @@ public class UnaryExpr <: Expr { right.prettyPrint(printer) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "UnaryExpr") + printer.print("oper", oper) + printer.printObject("right", right) + } + public mut prop oper: Token { get() { oper_ @@ -206,6 +237,12 @@ public class AssignExpr <: Expr { right.prettyPrint(printer) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "AssignExpr") + printer.printObject("left", left) + printer.printObject("right", right) + } + public mut prop left: Expr { get() { left_ @@ -249,6 +286,11 @@ public open class RefExpr <: Expr { public override func prettyPrint(printer: PrettyPrinter): Unit { printer.append(identifier.value) } + + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "RefExpr") + printer.print("identifier", identifier) + } } public class Block <: Expr { @@ -285,6 +327,11 @@ public class Block <: Expr { printer.append("\n}\n") } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "Block") + printer.printList("nodes", nodes) + } + public mut prop nodes: ArrayList { get() { nodes_ @@ -328,6 +375,13 @@ public class IfExpr <: Expr { elseBranch.prettyPrint(printer) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "IfExpr") + printer.printObject("condition", condition) + printer.printObject("ifBlock", ifBlock) + printer.printObject("elseBranch", elseBranch) + } + public mut prop condition: Expr { get() { condition_ @@ -381,6 +435,12 @@ public class WhileExpr <: Expr { block.prettyPrint(printer) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "WhileExpr") + printer.printObject("condition", condition) + printer.printObject("block", block) + } + public mut prop condition: Expr { get() { condition_ @@ -434,6 +494,12 @@ public open class CallExpr <: Expr { printer.append(")") } + public open override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "CallExpr") + printer.printObject("callee", callee) + printer.printList("arguments", arguments) + } + public prop callee: Node { get() { callee_ @@ -474,6 +540,12 @@ public class ReturnExpr <: Expr { } } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "ReturnExpr") + printer.printOptionalObject("expr", expr) + printer.print("keyword", keyword) + } + public mut prop expr: ?Expr { get() { expr_ @@ -513,6 +585,11 @@ public class JumpExpr <: Expr { printer.append(keyword.value) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "JumpExpr") + printer.print("keyword", keyword) + } + public mut prop keyword: Token { get() { keyword_ @@ -542,6 +619,12 @@ public open class MemberAccess <: Expr { printer.append(".${field.value}") } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "MemberAccess") + printer.printObject("baseExpr", baseExpr) + printer.print("field", field) + } + public open override func traverse(v: Visitor): R { v.visit(this) } @@ -581,6 +664,11 @@ public class PrimitiveTypeExpr <: Expr { printer.append(keyword.value) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "PrimitiveTypeExpr") + printer.print("keyword", keyword) + } + public override func traverse(v: Visitor): R { v.visit(this) } @@ -611,6 +699,11 @@ public class ThisSuperExpr <: Expr { printer.append(keyword.value) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "ThisSuperExpr") + printer.print("keyword", keyword) + } + public override func traverse(v: Visitor): R { v.visit(this) } diff --git a/src/visitor/Node.cj b/src/visitor/Node.cj index 8097d95..d2cdee4 100644 --- a/src/visitor/Node.cj +++ b/src/visitor/Node.cj @@ -1,6 +1,6 @@ package cjcj.visitor -import cjcj.prettyPrinter.PrettyPrinter +import cjcj.prettyPrinter.{PrettyPrinter, YamlPrintable, YamlPrinter} import std.collection.ArrayList import std.deriving.Derive @@ -22,7 +22,7 @@ public struct NodeId <: Hashable { } } -public abstract class Node <: Hashable & Equatable { +public abstract class Node <: Hashable & Equatable & YamlPrintable { private var id_: NodeId public Node(id: NodeId) { @@ -36,6 +36,20 @@ public abstract class Node <: Hashable & Equatable { */ public func prettyPrint(printer: PrettyPrinter): Unit + public func yamlPrint(printer: YamlPrinter): Unit + + public func prettyPrint(): String { + let printer: PrettyPrinter = PrettyPrinter() + prettyPrint(printer) + return printer.toString() + } + + public func yamlPrint(): String { + let printer: YamlPrinter = YamlPrinter() + yamlPrint(printer) + return printer.toString() + } + public mut prop id: NodeId { get() { id_ @@ -74,6 +88,11 @@ public class Argument <: Node { expr.prettyPrint(printer) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "Argument") + printer.printObject("expr", expr) + } + public mut prop expr: Node { get() { expr_ @@ -106,6 +125,11 @@ public class Program <: Node { ) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "Program") + printer.printList("decls", decls) + } + public mut prop decls: ArrayList { get() { decls_ @@ -143,6 +167,11 @@ public class Body <: Node { printer.append("\n}") } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "Body") + printer.printList("decls", decls) + } + public override func traverse(v: Visitor): R { v.visit(this) } diff --git a/src/visitor/Reference.cj b/src/visitor/Reference.cj index 33a5d1b..0c99bc8 100644 --- a/src/visitor/Reference.cj +++ b/src/visitor/Reference.cj @@ -1,6 +1,6 @@ package cjcj.visitor -import cjcj.prettyPrinter.PrettyPrinter +import cjcj.prettyPrinter.{PrettyPrinter, YamlPrinter} import cjcj.scanner.Token import std.collection.* @@ -21,6 +21,10 @@ public open class Reference <: Expr & Equatable & ToString { printer.append(identifier.value) } + public open override func yamlPrint(_: YamlPrinter): Unit { + throw UnsupportedException("Unimplemented method") + } + public open override func traverse(_: Visitor): R { throw UnsupportedException("Unimplemented method") } diff --git a/src/visitor/TypeNodes.cj b/src/visitor/TypeNodes.cj index 2aed85f..3de62b1 100644 --- a/src/visitor/TypeNodes.cj +++ b/src/visitor/TypeNodes.cj @@ -1,6 +1,6 @@ package cjcj.visitor -import cjcj.prettyPrinter.PrettyPrinter +import cjcj.prettyPrinter.{PrettyPrinter, YamlPrinter} import cjcj.scanner.* /* @@ -32,6 +32,11 @@ public open class TypeNode <: Node { public open override func prettyPrint(_: PrettyPrinter): Unit { } + public open override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("typeParameterName", typeParameterName) + printer.print("typeName", typeName) + } + public mut prop typeParameterName: Token { get() { typeParameterName_ @@ -73,6 +78,12 @@ public class PrimitiveType <: TypeNode { printer.append(typeName.value) } + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "PrimitiveType") + super.yamlPrint(printer) + printer.print("primitive", true) + } + private func isPrimitive(typeName: Token): Bool { TokenKindHelper.CHAR_LANG_TYPES.iterator().any({t => t == typeName.kind}) } @@ -91,4 +102,10 @@ public class RefType <: TypeNode { super.prettyPrint(printer) printer.append(typeName.value) } + + public override func yamlPrint(printer: YamlPrinter): Unit { + printer.print("type", "RefType") + super.yamlPrint(printer) + printer.print("primitive", false) + } }