Language 84

File

language84-0.5/84.84

Block
    Let root_path (parse_command_line)
    In
    Let packages (parse_packages root_path)
    In
    Let paths (LIST.map packages [Func p p.path])
    Let program (compile packages)
    In
    Begin
        (write_dependencies_file root_path paths)
        (emit root_path program)
    End

Where

Define (parse_command_line)
    Let usage "usage: 84 <program>"
    In
    Let root_path
        If [(OS.fetch_argc) = 2]
            (OS.fetch_arg 1)
            (OS.die usage)
    In
    root_path

Define (parse_packages root_path)
    Let STRING_SET (SEARCH.SET STRING.compare)
    In
    Define (parse_file path)
        Let file_name (STRING.append path ".84")
        In
        Let text
            Let file (OS.file_open file_name)
            In
            Let text (OS.file_read_all file)
            Do (OS.file_close file)
            In
            text
        In
        Match (PARSE.file text)
        | 'succeed.expr expr
        | 'fail.{message i}
            Begin
                (SYNTAX_ERROR.show file_name text message i)
                (OS.die "Compilation failed.")
            End
        ;
    Define (push_paths stack filter paths)
        (LIST.reduce paths {stack filter}
            Func {{stack filter} path}
                Match (STRING_SET.search filter path)
                | 'just._ {stack filter}
                | 'nothing {[path & stack] (STRING_SET.insert filter path)}
                ;)
    In
    Let packages
        Let packages 'nil
        Let stack [root_path & 'nil]
        Let filter (STRING_SET.new [root_path & 'nil])
        In
        Unfold {packages stack filter}
            Match stack
            | 'nil packages
            | 'cons.{path stack}
                Let expr (parse_file path)
                In
                Let imports (PACKAGE.gather_imports expr)
                In
                Let package {: path : imports : expr}
                Let {stack filter} (push_paths stack filter imports)
                In
                (Fold [package & packages] stack filter)
            ;
    In
    (PACKAGE.sort_by_dependence packages)

Define (write_dependencies_file root_path paths)
    Let file_name (STRING.append root_path ".c.d")
    In
    Let file (OS.file_create file_name)
    In
    Begin
        (OS.file_write file (STRING.append root_path ".c:"))
        Unfold paths
            Match paths
            | 'nil
                Begin
                    (OS.file_write file "\n")
                    (OS.file_close file)
                End
            | 'cons.{path paths}
                Begin
                    (OS.file_write file
                        (STRING.concat [Right " " & path & ".84" & 'nil]))
                    (Fold paths)
                End
            ;
    End

Define (compile program)
    Let {_ program}
        (LIST.fold program {1 'nil}
            Func {package {i packages}}
                Let {init i functions}
                    (COMPILE.lift_functions i
                        (COMPILE.collect_free_variables
                            (COMPILE.elaborate_recursion package.expr)))
                In
                Let package
                    {
                    : path package.path
                    : imports package.imports
                    : init
                    : functions
                    }
                In
                {i [package & packages]})
    In
    (COMPILE.collect_constants program)

Define (emit root_path program)
    Let file (OS.file_create (STRING.append root_path ".c"))
    In
    Define (write string)
        (OS.file_write file string)
    In
    Begin
        (C.emit (C.elaborate program) write)
        (OS.file_close file)
    End

Where

Let C Package "c"
Let COMPILE Package "compile"
Let LIST Package "list"
Let OS Package "os"
Let PACKAGE Package "package"
Let PARSE Package "parse"
Let SEARCH Package "search"
Let STDIO Package "stdio"
Let STRING Package "string"
Let SYNTAX_ERROR Package "syntax_error"