175 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
ns nonavosa_rail
 | 
						|
 | 
						|
pub mod train {
 | 
						|
 | 
						|
    pub int Train {
 | 
						|
        name: String
 | 
						|
        primary_color: Color
 | 
						|
        destination: String
 | 
						|
 | 
						|
        fn blow_horn(): IO
 | 
						|
        fn set_volume_by(factor: Number)
 | 
						|
    }
 | 
						|
 | 
						|
    pub enum Color {
 | 
						|
        White, Blue, Red
 | 
						|
    }
 | 
						|
 | 
						|
    pub fn int Printer {
 | 
						|
        (message: String): IO
 | 
						|
    }
 | 
						|
 | 
						|
    pub fn create(props: Props<Train> & { printer: Printer }): Train = SimpleTrain { ...props } with { volume = 80.0 }
 | 
						|
 | 
						|
    abs impl : Train {
 | 
						|
 | 
						|
        #get #set
 | 
						|
        fld volume: Double
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    impl SimpleTrain : AbstractTrain {
 | 
						|
 | 
						|
        printer: Printer
 | 
						|
 | 
						|
        override fn set_volume(volume) {
 | 
						|
            if (volume < 0 || volume > 100) {
 | 
						|
                throw IllegalArgumentException {
 | 
						|
                    message: `Volume $volume is outside of bounds 0-100.`,
 | 
						|
                    argument: volume
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            this.volume = volume
 | 
						|
        }
 | 
						|
 | 
						|
        impl fn blow_horn() = printer(`Train named $name is blowing it's horn at volume $volume!`)
 | 
						|
             -> { s => s.append('Hello from SimpleTrain!') }
 | 
						|
 | 
						|
        impl fn set_volume_by(factor) = set_volume(volume * factor)
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
fn main(args) {
 | 
						|
    let train = train::create {
 | 
						|
        name: 'Test Train',
 | 
						|
        primary_color: train::Color::Blue,
 | 
						|
        destination: 'Nonavosa Central',
 | 
						|
        printer: { msg => println(msg) }
 | 
						|
    }
 | 
						|
    train.set_volume_by(1.1)
 | 
						|
    train.blow_horn()
 | 
						|
 | 
						|
    let anonymous_train = train::Train {
 | 
						|
        name: 'Anonymous Train',
 | 
						|
        primary_color: train::Color::Red,
 | 
						|
        destination: 'Nonavosa North',
 | 
						|
 | 
						|
        impl fn blow_horn() = println('Choo Choo!')
 | 
						|
        impl fn set_volume_by = throw MethodNotSupported
 | 
						|
    }
 | 
						|
 | 
						|
    try {
 | 
						|
        anonymous_train.set_volume_by(3.0)
 | 
						|
    } catch (e: MethodNotSupported) {
 | 
						|
        println e.message
 | 
						|
    }
 | 
						|
 | 
						|
    anonymous_train.blow_horn() -> { println('After blow horn, assuming nothing went wrong before') }
 | 
						|
}
 | 
						|
 | 
						|
// some other file
 | 
						|
 | 
						|
fn log_printer(message) impl nonavosa_rail::train::Printer = msg =>
 | 
						|
    io::open_file('log.txt', io::Mode::Append)
 | 
						|
        -> { f => f.append(msg) }
 | 
						|
        -> io::close_file
 | 
						|
 | 
						|
fn main() {
 | 
						|
    nonavosa_rail::main(log_printer)
 | 
						|
}
 | 
						|
 | 
						|
// io.dm
 | 
						|
 | 
						|
ns io
 | 
						|
 | 
						|
decl extern fn println(s: String)
 | 
						|
 | 
						|
#target[lua]
 | 
						|
decl extern fn _open_file(filename: String, mode: String): LuaTable
 | 
						|
 | 
						|
#target[lua]
 | 
						|
pub fn open_file(filename: String, mode: Mode): IO<File, LuaError> {
 | 
						|
    try {
 | 
						|
        let lua_file_handle = lua {% fs.open(${filename}, ${mode.as_lua_string()}) %}
 | 
						|
        Success(LuaFile { lua_file_handle })
 | 
						|
    } catch (e: LuaError) {
 | 
						|
        Failure(e)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#target[lua]
 | 
						|
pub fn close_file(file): impl IO<File, LuaError> = file.close()
 | 
						|
 | 
						|
pub int File : Stream
 | 
						|
 | 
						|
#target[lua]
 | 
						|
impl LuaFile : File {
 | 
						|
 | 
						|
    #get
 | 
						|
    fld lua_file_handle
 | 
						|
 | 
						|
    impl fn append(data) {
 | 
						|
        try {
 | 
						|
            lua {% ${lua_file_handle}.write(${data}) %}
 | 
						|
            Success(self)
 | 
						|
        } catch (e: LuaError) {
 | 
						|
            Failure(e)
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    impl fn close() {
 | 
						|
        try {
 | 
						|
            lua {% ${lua_file_handle}.close() %}
 | 
						|
            Success
 | 
						|
        } catch (e: LuaError) {
 | 
						|
            Failure(e)
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
pub enum Mode {
 | 
						|
    Append, Write, Read
 | 
						|
}
 | 
						|
 | 
						|
pub enum IO<S: Stream = Stream, E?> : Chainable<IO<S, E>> {
 | 
						|
    Success(stream?: S) {
 | 
						|
        impl fn call() {
 | 
						|
            try {
 | 
						|
                do_call(stream)
 | 
						|
            } catch (e: E) {
 | 
						|
                Failure(e)
 | 
						|
            }
 | 
						|
        }
 | 
						|
    },
 | 
						|
    Failure(_) {
 | 
						|
        impl fn call() = self
 | 
						|
    };
 | 
						|
 | 
						|
    fn <N: Stream> do_call(stream: S): IO<N, E>
 | 
						|
}
 | 
						|
 | 
						|
pub int Stream {
 | 
						|
    fn append(data: String): IO<Self>
 | 
						|
    fn close(): IO
 | 
						|
}
 | 
						|
 | 
						|
// chain.dm
 | 
						|
 | 
						|
pub fn int Chainable<N> {
 | 
						|
    (): N
 | 
						|
}
 |