Source

kink / src / main / kink / internal / Start.kn

#!/usr/bin/env kink
# vim: et sw=4 sts=4

# Copyright (c) 2013 Miyakawa Taku
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

# Sart the program
:start = { (:Args)
    { _parse_and_do_command(Args) } .try.switch(
        [true :Result] { Result }
        [false :Exception] {
            Exception.setStackTrace([])
            Exception.throw
        }
    )
}

# Help text of the kink command
:_help = { (:Out)
    use('USING.using')
    use('org.kink_lang.kink.Value')
    using(Value.getClassLoader.getResourceAsStream('org/kink_lang/kink/help.txt')) {
        \0.lines.map {
            \0.chomp
        } .loop {
            Out.printline(\0)
        }
    }
}

# Parse Args as command and do it
:_parse_and_do_command = { (:Args)
    use('PARSE_COMMAND')
    :Execute = ()
    :Parser = PARSE_COMMAND.parser
    .strictorder
    .noarg('--help' '-h') {
        _help(stdout)
        exit
    }
    .noarg('--version' '-v') {
        use('KINK_VERSION')
        printline(expand('kink #{KINK_VERSION.version}'))
        exit
    }
    .reqarg('--execute' '-e') {
        :Execute.solid = \0
    }
    .onerror { (:Message)
        stderr.printline(Message)
        stderr.printline('')
        _help(stderr)
        die
    }
    :Args_after_opts = Parser.parse(Args)
    switch(
        { Execute.str?? } {
            :Program = Execute.program('(execute)')
            _run(Program Args_after_opts)
        }
        { ! Args_after_opts.any? } {
            use('REPL')
            REPL.repl.run
        }
        { Args_after_opts.first == '-' } {
            :Program = stdin.bytes.program('(stdin)')
            _run(Program Args_after_opts.drophead(1))
        }
        (any) {
            :Filename = Args_after_opts.first
            :Program = { path(Filename).program } .try.switch(
                [true :Result] { Result }
                [false :Exception] { die(Exception.message) }
            )
            _run(Program Args_after_opts.drophead(1))
        }
    )
}

# Run Program with Argv
:_run = { (:Program :Argv)
    :Env = module('CORE').child(
        'Argv' Argv
        'show' { > :Env
            '<env:#of=' + Program.name.show + ':hash=' + Env.hash + '>'
        }
    )
    Program.valid? || die(expand('#{Program.errordesc}'))
    :runsource = Program.compile.notrace
    runsource(Env)
}