Kind2/base/App.kind
2021-07-11 17:49:39 -03:00

190 lines
4.6 KiB
Plaintext

// The App type is parametric on two types: the local and global state types.
App.State: Type
Pair<Type, Type>
// Gets the local state type of the App type
App.State.local: App.State -> Type
Pair.fst<Type,Type>
// Gets the global state type of the App type
App.State.global: App.State -> Type
Pair.snd<Type,Type>
// Creates a new App type
App.State.new<A: Type, B: Type>: App.State
Pair.new<Type,Type>(A, B)
// The App's store holds its local and global states
type App.Store <S: App.State> {
new(
local: App.State.local(S)
global: App.State.global(S)
)
}
// An App is a tuple of functions defining its behaviors
type App <S: App.State> {
new(
init: App.Init<S> // initial state
draw: App.Draw<S> // render function
when: App.When<S> // local event handler
tick: App.Tick<S> // global tick handler
post: App.Post<S> // global post handler
)
}
// The initial state
App.Init<S: App.State>: Type
App.Store<S>
// The render function receives a state and returns a virtual DOM
App.Draw<S: App.State>: Type
((state: App.Store<S>) -> DOM)
// The local event handler receives the event, the state, and returns an IO
// action. That IO action may return an updated local state.
App.When<S: App.State>: Type
((event: App.Event, state: App.Store<S>) -> IO<Maybe<App.State.local(S)>>)
// The global tick handler receives an interval of time, the global state, and
// must return the updated global state.
App.Tick<S: App.State>: Type
((tick: U64, glob: App.State.global(S)) -> App.State.global(S))
// The global post handler receives:
// - time: 64 bits, representing time in 62.5s ticks. Equal to UTC_TIME / 62.5
// - room: 64 bits, representing the room this post was posted to.
// - addr: 160 bits, the user identifier, represented as its Ethereum address
// - data: 256 bits, the contents of the post
// - glob: the current global state of the app
// It must return the updated global state.
App.Post<S: App.State>: Type
((tick: U64, room: String, addr: String, data: String, glob: App.State.global(S)) -> App.State.global(S))
type App.Event {
// Occurs when the app is initialized
init(
time: U64
user: App.UserAddress
info: App.EnvInfo
)
// Occurs 60 frames per second
frame(
time: U64
info: App.EnvInfo
)
// Occurs when the user presses a mouse button over an element and before it is released
mouse_down(
time: U64
button: U16
)
// Occurs when a user releases a mouse button over an element
mouse_up(
time: U64
button: U16
)
// Occurs when the user presses a keyboard key down
key_down(
time: U64
code: U16
)
// Occurs when the user releases a keyboard key up
key_up(
time: U64
code: U16
)
// The event occurs when the mouse moves
mouse_move(
time: U64
id: String
mouse_pos: Pair<U32, U32>
)
// The event occurs when the pointer is moved onto an element, or onto one of its children
mouse_over(
time: U64
id: String
)
// The event occurs when the user clicks on an element. It's fired after the mousedown and mouseup events
mouse_click(
time: U64
id: String
action: String
)
// Occurs when there is a new text input in a DOM element
input(
time: U64
id: String
text: String
)
}
type App.EnvInfo {
new(
screen_size: Pair<U32, U32>
mouse_pos: Pair<U32, U32>
)
}
App.UserAddress: Type
String
// Default init
App.no_init<S: App.State>: Unit
unit
// Default draw
App.no_draw<S: App.State>: App.Draw<S>
(state) DOM.text("")
// Default when
App.no_when<S: App.State>: App.When<S>
(event, state) App.pass!
// Default tick
App.no_tick<S: App.State>: App.Tick<S>
(tick, glob) glob
// Default post
App.no_post<S: App.State>: App.Post<S>
(tick, room, addr, data, glob) glob
App.do<S: App.State>(call: String, param: String): IO<Maybe<App.State.local<S>>>
IO {
IO.do(call, param)
App.pass<S>
}
App.pass<S: App.State>: IO<Maybe<App.State.local(S)>>
IO {
return none
}
App.new_post<S: App.State>(room: String, data: String): IO<Maybe<App.State.local<S>>>
IO {
App.do<S>("post", room | ";" | data)
App.pass<S>
}
App.print<S: App.State>(str: String): IO<Maybe<App.State.local<S>>>
IO {
IO.print(str)
App.pass<S>
}
App.set_local<S: App.State>(value: App.State.local<S>): IO<Maybe<App.State.local<S>>>
IO {
return some(value)
}
App.watch<S: App.State>(room: String): IO<Maybe<App.State.local<S>>>
App.do<S>("watch", room)
App.unwatch<S: App.State>(room: String): IO<Maybe<App.State.local<S>>>
App.do<S>("unwatch", room)
App.room_zero: String
"0000000000000000"
App.room(name: String): String
String.take(16, Crypto.Keccak.hash(name))