A "high-level" language for the Gameboy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

83 lines
2.1 KiB

  1. // import { convertASM } from "./asm"
  2. import { convertIR, prettyPrintIR } from "./ir"
  3. import { parse } from "./parser"
  4. import { inspect } from "util"
  5. import type { Attr, Decl, Stmt, Type, VarDecl } from "./ast"
  6. type SymbolDefn = {
  7. attrs: Array<Attr>,
  8. name: string,
  9. type: Type
  10. }
  11. type SymbolMap = {
  12. [name: string]: SymbolDefn
  13. }
  14. // TODO: Support more than one TU
  15. export const compile = (fileName: string, source: string): string => {
  16. // 1. Parse
  17. const ast = parse(source)
  18. // 2. Partition declarations and statements
  19. const decls = ast.filter((x): x is Decl => x.type == "decl")
  20. const stmts = ast.filter((x): x is Stmt => x.type == "stmt")
  21. // 3. Create top-level symbol map
  22. const symbols = processDecls(decls)
  23. // TODO: Support declaring types other than U8/S8
  24. const asmDecls = Object.values(symbols).map(symbol => `${symbol.name}:: DB`)
  25. // TODO: Some form of type-checking
  26. // 4. Generate IR
  27. const ir = convertIR(stmts)
  28. console.log("=== IR === ")
  29. console.log(ir.map(prettyPrintIR).join("\n"))
  30. // 5. Generate code
  31. /* const insns = convertASM(ir)
  32. let output = ''
  33. if (asmDecls.length > 0) {
  34. output += `SECTION "${fileName} Data", WRAM0\n\n`
  35. output += asmDecls.join("\n")
  36. output += "\n\n"
  37. }
  38. if (insns.length > 0) {
  39. output += `SECTION "${fileName} Code", ROM0\n\n`
  40. output += insns.join("\n")
  41. }
  42. console.log("=== ASM === ")
  43. return output */
  44. return ''
  45. }
  46. export const processDecls = (decls: Array<Decl>): SymbolMap => decls.reduce(processDecl, {})
  47. export const processDecl = (symbols: SymbolMap, decl: Decl): SymbolMap => {
  48. const symbol = processVarDecl(symbols, decl)
  49. return {
  50. ...symbols,
  51. [symbol.name]: symbol,
  52. }
  53. }
  54. export const processVarDecl = (symbols: SymbolMap, decl: VarDecl): SymbolDefn => {
  55. if (typeof symbols[decl.name] !== 'undefined') {
  56. throw new Error(`a variable named \`${decl.name}' is already defined`)
  57. }
  58. return {
  59. attrs: decl.attrs,
  60. name: decl.name,
  61. type: decl.args.type,
  62. }
  63. }