8.1.3. Nodejs
Nodejs is the main target to compile console applications.
Note
The following is draft material. It needs more details to be implemented.
8.1.3.1. Error
Nodejs has 4 categories of errors
Standard javascript errors like
EvalError,SyntaxError, etc. These errors shall not occur in compiled javascript code.System errors triggered by the underlying operating systems like open a file that does not exist.
User specified errors triggered by the application code.
Assertion errors.
There are 3 mechanism to raise an error:
Throw an exception. Error handling via
try {...} catch (err) {...}.Error first in callbacks
(err, ...) => { if (err) {...} ...}. A non null error object indicates an error.Event emitters emit error events
connection.on('error', (err) => {...}).
A system error has the following mandatory and optional properties:
errno: negative numbers according to libuv.
code: The string error code (see common system errors)
syscall: The name of the system call which failed e.g.
openmessage: A system-provided human-readable description of the error
(opt) path: The file path when reporting a file system error
(opt) dest: The file path destination when reporting a file system error
(opt) (port, address, …)
Nodejs has an error object with certain fields. The most important ones are syscall, code and message. It might be best to define a record in alba which has these three fields
record Error :=
syscall: String
code: String
message: String
8.1.3.2. IO Monad
Actions are done within some kind of IO monad. There is some builtin type
IO:
IO: Any -> Any
IO.return {A}: A -> IO A
IO.(>>=) {A B}: IO A -> (A -> IO B) -> IO B
Many actions have the possibility to fail. To describe failures the builtin
Result type is used.
class Result {E A: Any} :=
ok: A -> Result
error: E -> Result
Result.(>>=) {E A}: Result E A -> (A -> Result E B) -> Result E B
:= case
\ (ok a) f := f a
\ (error e) _ := error e
Result.catch {E A}: Result E A -> (E -> Result E A) -> Result E A
:=
\ (ok a) _ := ok a
\ (error e) f := f e
Using IO and Result we create the type IOE which is an io action
which can fail.
record IOE (A: Any) :=
io: IO (Result Error A)
IOE.ok {A} (a: A): IOE A :=
record [ ok a |> return ]
IOE.error {A} (e: Error): IOE A :=
record [ error e |> return ]
IOE.(>>=) {A B} (m: IOE A) (f: A -> IOE B): IOE B :=
record [
do
r := io m
inspect r case
\ (ok a) :=
io <| f a
\ (error e) :=
return <| error e
]
IOE.catch {A} (m: IOE A) (f: Error -> IOE A): IOE A :=
record [ catch (io m) (f >> io) ]
8.1.3.3. Buffer
Buffers are needed to do input/output. Buffers have a capacity and a size.
Buffer: Any
allocate: UInt -> IOE Buffer -- no more memory error
free: Buffer -> IOE Unit -- already freed error
toString: Buffer -> IOE String -- already freed error
fromString: String -> IOE Buffer -- no more memory error
8.1.3.4. File System
- ::
File: Any
stdin: File stdout: File stderr: File
open: String -> Mode -> IOE File close: File -> IOE Unit
read: File -> Buffer -> IOE Bool – ok or end of file reached write: File -> Buffer -> IOE Unit