diff --git a/zss/firmware/all.ts b/zss/firmware/all.ts index ba9ca262..bc3c63d1 100644 --- a/zss/firmware/all.ts +++ b/zss/firmware/all.ts @@ -1,76 +1,73 @@ import { maptostring } from 'zss/chip' +import { api_error, register_read, register_write } from 'zss/device/api' import { createfirmware } from 'zss/firmware' -import { gadgethyperlink, gadgettext } from 'zss/gadget/data/api' import { isnumber } from 'zss/mapping/types' -import { memoryreadcontext } from 'zss/memory' +import { memoryreadchip, memoryreadcontext, memorysetbook } from 'zss/memory' +import { createbook } from 'zss/memory/book' import { ARG_TYPE, readargs } from './wordtypes' export const ALL_FIRMWARE = createfirmware({ - get(chip, name) { + get() { return [false, undefined] }, - set(chip, name, value) { + set() { return [false, undefined] }, - shouldtick(chip) { - // - }, - tick(chip) { - // - }, - tock(chip) { - // - }, + shouldtick() {}, + tick() {}, + tock() {}, }) - .command('clear', (chip, words) => { - const name = maptostring(words[0]) - chip.set(name, undefined) - return 0 - }) - .command('end', (chip) => { - // future, this will also afford giving a return value #end - chip.endofprogram() - return 0 - }) - .command('give', (chip, words) => { - const [name, maybevalue, ii] = readargs(memoryreadcontext(chip, words), 0, [ - ARG_TYPE.STRING, - ARG_TYPE.MAYBE_NUMBER, - ]) - - const maybecurrent = chip.get(name) - const current = isnumber(maybecurrent) ? maybecurrent : 0 - const value = maybevalue ?? 1 - - // giving a non-numerical value - if (!isnumber(value)) { - // todo: raise warning ? - return 0 - } + // memory / app state + .command('book', (chip, words) => { + const [maybetarget, maybeaction] = readargs( + memoryreadcontext(chip, words), + 0, + [ARG_TYPE.STRING, ARG_TYPE.STRING], + ) - // returns true when setting an unset flag - const result = maybecurrent === undefined ? 1 : 0 - if (result && ii < words.length) { - chip.command(...words.slice(ii)) + const ltarget = maybetarget.toLowerCase() + const laction = maybeaction.toLowerCase() + switch (laction) { + case 'create': + memorysetbook(createbook(ltarget, [])) + break + default: + // TODO raise error of unknown action + break } - // update flag - chip.set(name, current + value) - return result - }) - .command('idle', (chip) => { - chip.yield() return 0 }) - // .command('if' // stub-only, this is a lang feature - .command('lock', (chip) => { - chip.lock(chip.id()) + .command('register', (chip, words) => { + const memory = memoryreadchip(chip.id()) + const maybeplayer = memory.object?.stats?.player ?? '' + const [action, name] = readargs(memoryreadcontext(chip, words), 0, [ + ARG_TYPE.STRING, + ARG_TYPE.STRING, + ]) + switch (action.toLowerCase()) { + case 'read': + register_read(chip.senderid(), name, maybeplayer) + break + case 'write': + register_write(chip.senderid(), name, chip.get(name), maybeplayer) + break + default: + api_error( + chip.senderid(), + 'register', + `unknown #regsiter [action] ${action}`, + maybeplayer, + ) + break + } return 0 }) - // .command('restart' // this is handled by a built-in 0 label - .command('restore', (chip, words) => { - chip.restore(maptostring(words[0])) + // flags + .command('clear', (chip, words) => { + const name = maptostring(words[0]) + chip.set(name, undefined) return 0 }) .command('set', (chip, words) => { @@ -111,25 +108,56 @@ export const ALL_FIRMWARE = createfirmware({ chip.set(name, newvalue) return 0 }) - .command('unlock', (chip) => { - chip.unlock() + .command('give', (chip, words) => { + const [name, maybevalue, ii] = readargs(memoryreadcontext(chip, words), 0, [ + ARG_TYPE.STRING, + ARG_TYPE.MAYBE_NUMBER, + ]) + + const maybecurrent = chip.get(name) + const current = isnumber(maybecurrent) ? maybecurrent : 0 + const value = maybevalue ?? 1 + + // giving a non-numerical value + if (!isnumber(value)) { + // todo: raise warning ? + return 0 + } + + // returns true when setting an unset flag + const result = maybecurrent === undefined ? 1 : 0 + if (result && ii < words.length) { + chip.command(...words.slice(ii)) + } + + // update flag + chip.set(name, current + value) + return result + }) + // lifecycle + .command('idle', (chip) => { + chip.yield() return 0 }) - .command('zap', (chip, words) => { - chip.zap(maptostring(words[0])) + .command('end', (chip) => { + // future, this will also afford giving a return value #end + chip.endofprogram() return 0 }) - // gadget output & ui - .command('text', (chip, words) => { - const text = words.map(maptostring).join('') - gadgettext(chip, text) + // message mangement + .command('lock', (chip) => { + chip.lock(chip.id()) + return 0 + }) + .command('restore', (chip, words) => { + chip.restore(maptostring(words[0])) return 0 }) - .command('hyperlink', (chip, args) => { - // package into a panel item - const [labelword, inputword, ...words] = args - const label = maptostring(labelword) - const input = maptostring(inputword) - gadgethyperlink(chip, label, input, words) + .command('unlock', (chip) => { + chip.unlock() + return 0 + }) + .command('zap', (chip, words) => { + chip.zap(maptostring(words[0])) return 0 }) diff --git a/zss/firmware/cli.ts b/zss/firmware/cli.ts new file mode 100644 index 00000000..1efea976 --- /dev/null +++ b/zss/firmware/cli.ts @@ -0,0 +1,21 @@ +import { createfirmware } from 'zss/firmware' + +export const CLI_FIRMWARE = createfirmware({ + get(chip, name) { + return [false, undefined] + }, + set(chip, name, value) { + return [false, undefined] + }, + shouldtick(chip) { + // + }, + tick(chip) { + // + }, + tock(chip) { + // + }, +}).command('stub', (chip, words) => { + return 0 +}) diff --git a/zss/firmware/gadget.ts b/zss/firmware/gadget.ts new file mode 100644 index 00000000..d77aa857 --- /dev/null +++ b/zss/firmware/gadget.ts @@ -0,0 +1,114 @@ +import { maptostring } from 'zss/chip' +import { createfirmware } from 'zss/firmware' +import { + gadgetcheckscroll, + gadgetcheckset, + gadgethyperlink, + gadgetpanel, + gadgettext, +} from 'zss/gadget/data/api' +import { PANEL_TYPE, PANEL_TYPE_MAP } from 'zss/gadget/data/types' +import { ispresent } from 'zss/mapping/types' +import { + memorycreateeditframe, + memorycreateviewframe, + memoryreadchip, + memoryreadcontext, + memoryresetframes, +} from 'zss/memory' + +import { ARG_TYPE, readargs } from './wordtypes' + +export const GADGET_FIRMWARE = createfirmware({ + get() { + return [false, undefined] + }, + set(chip, name, value) { + // how about we split this out into gadget firmware + // we monitor changes on shared values here + gadgetcheckset(chip, name, value) + // return has unhandled + return [false, undefined] + }, + shouldtick() {}, + tick(chip) { + const memory = memoryreadchip(chip.id()) + + let withname = 'scroll' + if (ispresent(memory.object?.name)) { + withname = memory.object.name + } + + gadgetpanel(chip, 'scroll', PANEL_TYPE.SCROLL, undefined, withname) + }, + tock(chip) { + gadgetcheckscroll(chip) + }, +}) + // gadget output & ui + .command('gadget', (chip, words) => { + const context = memoryreadcontext(chip, words) + + const [edge] = readargs(context, 0, [ARG_TYPE.STRING]) + const edgeConst = PANEL_TYPE_MAP[edge.toLowerCase()] + if (edgeConst === PANEL_TYPE.SCROLL) { + const [, name, size] = readargs(context, 0, [ + ARG_TYPE.STRING, + ARG_TYPE.MAYBE_STRING, + ARG_TYPE.MAYBE_NUMBER, + ]) + gadgetpanel(chip, edge, edgeConst, size, name) + } else { + const [, size, name] = readargs(context, 0, [ + ARG_TYPE.STRING, + ARG_TYPE.MAYBE_NUMBER, + ARG_TYPE.MAYBE_STRING, + ]) + gadgetpanel(chip, edge, edgeConst, size, name) + } + + return 0 + }) + .command('frame', (chip, words) => { + const memory = memoryreadchip(chip.id()) + const [maybetarget, maybetype, maybeboard] = readargs( + memoryreadcontext(chip, words), + 0, + [ARG_TYPE.STRING, ARG_TYPE.MAYBE_STRING, ARG_TYPE.MAYBE_STRING], + ) + + const board = memory.board?.id ?? '' + + const ltarget = maybetarget.toLowerCase() + if (ltarget === 'reset') { + memoryresetframes(board) + } else if (ispresent(maybetype) && ispresent(maybeboard)) { + const ltype = maybetype.toLowerCase() + switch (ltype) { + case 'edit': + memorycreateeditframe(board, ltarget, maybeboard) + break + case 'view': + memorycreateviewframe(board, ltarget, maybeboard) + break + default: + // TODO raise error of unknown action + break + } + } + + return 0 + }) + .command('text', (chip, words) => { + const text = words.map(maptostring).join('') + gadgettext(chip, text) + return 0 + }) + .command('hyperlink', (chip, args) => { + // package into a panel item + const [labelword, inputword, ...words] = args + const label = maptostring(labelword) + const input = maptostring(inputword) + gadgethyperlink(chip, label, input, words) + return 0 + }) diff --git a/zss/firmware/loader.ts b/zss/firmware/loader.ts index 7a491e65..e70b4e05 100644 --- a/zss/firmware/loader.ts +++ b/zss/firmware/loader.ts @@ -3,17 +3,20 @@ import { FIRMWARE } from 'zss/firmware' import { CODE_PAGE_TYPE } from 'zss/memory/codepage' import { ALL_FIRMWARE } from './all' +import { CLI_FIRMWARE } from './cli' import { ZSS_FIRMWARE } from './zss' import { ZZT_FIRMWARE } from './zzt' const firmwares: Record = { all: ALL_FIRMWARE, + cli: CLI_FIRMWARE, zzt: ZZT_FIRMWARE, zss: ZSS_FIRMWARE, } export const CODE_PAGE_FIRMWARE = { [CODE_PAGE_TYPE.ERROR]: [], + [CODE_PAGE_TYPE.CLI]: ['all', 'cli'], [CODE_PAGE_TYPE.FUNC]: ['all'], [CODE_PAGE_TYPE.BOARD]: ['all'], [CODE_PAGE_TYPE.OBJECT]: ['all', 'zss', 'zzt'], diff --git a/zss/firmware/zzt.ts b/zss/firmware/object.ts similarity index 97% rename from zss/firmware/zzt.ts rename to zss/firmware/object.ts index bb7e520d..3cb7ccec 100644 --- a/zss/firmware/zzt.ts +++ b/zss/firmware/object.ts @@ -25,6 +25,7 @@ import { MAYBE_BOARD, MAYBE_BOARD_ELEMENT, boarddeleteobject, + boardelementapplycolor, boardelementread, boardfindplayer, boardterrainsetfromkind, @@ -267,7 +268,7 @@ function bookboardframeread( return { maybebook, maybeboard } } -export const ZZT_FIRMWARE = createfirmware({ +export const OBJECT_FIRMWARE = createfirmware({ get(chip, name) { // check consts first (data normalization) const maybeconst = maptoconst(name) @@ -377,7 +378,8 @@ export const ZZT_FIRMWARE = createfirmware({ chip.endofprogram() return 0 }) - .command('bind', (chip, words) => { + .command('bind', () => { + // return 0 }) .command('change', (chip, words) => { @@ -461,6 +463,16 @@ export const ZZT_FIRMWARE = createfirmware({ } return 0 }) + .command('color', (chip, words) => { + const memory = memoryreadchip(chip.id()) + const [value] = readargs(memoryreadcontext(chip, words), 0, [ + ARG_TYPE.COLOR, + ]) + if (ispresent(memory.object) && ispresent(value)) { + boardelementapplycolor(memory.object, value) + } + return 0 + }) .command('cycle', (chip, words) => { const [cyclevalue] = readargs(memoryreadcontext(chip, words), 0, [ ARG_TYPE.NUMBER, diff --git a/zss/firmware/zss.ts b/zss/firmware/zss.ts deleted file mode 100644 index 4079bb12..00000000 --- a/zss/firmware/zss.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { api_error, register_read, register_write } from 'zss/device/api' -import { createfirmware } from 'zss/firmware' -import { - gadgetcheckscroll, - gadgetcheckset, - gadgetpanel, -} from 'zss/gadget/data/api' -import { COLOR, PANEL_TYPE, PANEL_TYPE_MAP } from 'zss/gadget/data/types' -import { ispresent } from 'zss/mapping/types' -import { - memorycreateeditframe, - memorycreateviewframe, - memoryreadchip, - memoryreadcontext, - memoryresetframes, - memorysetbook, -} from 'zss/memory' -import { boardelementapplycolor, boardcreate } from 'zss/memory/board' -import { createbook } from 'zss/memory/book' -import { createcodepage } from 'zss/memory/codepage' - -import { ARG_TYPE, COLLISION, readargs } from './wordtypes' - -export const ZSS_FIRMWARE = createfirmware({ - get() { - return [false, undefined] - }, - set(chip, name, value) { - // we monitor changes on shared values here - gadgetcheckset(chip, name, value) - // return has unhandled - return [false, undefined] - }, - shouldtick() {}, - tick(chip) { - const memory = memoryreadchip(chip.id()) - const withname = memory.object?.name ?? memory.object?.kind ?? 'Scroll' - gadgetpanel(chip, 'scroll', PANEL_TYPE.SCROLL, undefined, withname) - }, - tock(chip) { - gadgetcheckscroll(chip) - }, -}) - .command('register', (chip, words) => { - const memory = memoryreadchip(chip.id()) - const maybeplayer = memory.object?.stats?.player ?? '' - const [action, name] = readargs(memoryreadcontext(chip, words), 0, [ - ARG_TYPE.STRING, - ARG_TYPE.STRING, - ]) - switch (action.toLowerCase()) { - case 'read': - register_read(chip.senderid(), name, maybeplayer) - break - case 'write': - register_write(chip.senderid(), name, chip.get(name), maybeplayer) - break - default: - api_error( - chip.senderid(), - 'register', - `unknown #regsiter [action] ${action}`, - maybeplayer, - ) - break - } - return 0 - }) - .command('color', (chip, words) => { - const memory = memoryreadchip(chip.id()) - const [value] = readargs(memoryreadcontext(chip, words), 0, [ - ARG_TYPE.COLOR, - ]) - if (ispresent(memory.object) && ispresent(value)) { - boardelementapplycolor(memory.object, value) - } - return 0 - }) - .command('gadget', (chip, words) => { - const context = memoryreadcontext(chip, words) - - const [edge] = readargs(context, 0, [ARG_TYPE.STRING]) - const edgeConst = PANEL_TYPE_MAP[edge.toLowerCase()] - if (edgeConst === PANEL_TYPE.SCROLL) { - const [, name, size] = readargs(context, 0, [ - ARG_TYPE.STRING, - ARG_TYPE.MAYBE_STRING, - ARG_TYPE.MAYBE_NUMBER, - ]) - gadgetpanel(chip, edge, edgeConst, size, name) - } else { - const [, size, name] = readargs(context, 0, [ - ARG_TYPE.STRING, - ARG_TYPE.MAYBE_NUMBER, - ARG_TYPE.MAYBE_STRING, - ]) - gadgetpanel(chip, edge, edgeConst, size, name) - } - - return 0 - }) - .command('book', (chip, words) => { - const [maybetarget, maybeaction] = readargs( - memoryreadcontext(chip, words), - 0, - [ARG_TYPE.STRING, ARG_TYPE.STRING], - ) - - const ltarget = maybetarget.toLowerCase() - const laction = maybeaction.toLowerCase() - switch (laction) { - case 'create': - memorysetbook( - createbook(ltarget, [ - createcodepage('@board title', { - board: boardcreate((board) => { - // todo, make it so you can clone an existing book - return board - }), - }), - createcodepage('@terrain dirt', { - terrain: { - char: 176, - bg: COLOR.BLACK, - color: COLOR.DKYELLOW, - collision: COLLISION.WALK, - }, - }), - createcodepage('@terrain dirt2', { - terrain: { - char: 176, - bg: COLOR.BLACK, - color: COLOR.DKGRAY, - collision: COLLISION.WALK, - }, - }), - createcodepage('@terrain wall', { - terrain: { - char: 177, - bg: COLOR.DKGREEN, - color: COLOR.GREEN, - collision: COLLISION.SOLID, - }, - }), - createcodepage('@terrain wall2', { - terrain: { - char: 176, - bg: COLOR.DKGREEN, - color: COLOR.GREEN, - collision: COLLISION.SOLID, - }, - }), - ]), - ) - break - default: - // TODO raise error of unknown action - break - } - - return 0 - }) - .command('frame', (chip, words) => { - const memory = memoryreadchip(chip.id()) - const [maybetarget, maybetype, maybeboard] = readargs( - memoryreadcontext(chip, words), - 0, - [ARG_TYPE.STRING, ARG_TYPE.MAYBE_STRING, ARG_TYPE.MAYBE_STRING], - ) - - const board = memory.board?.id ?? '' - - const ltarget = maybetarget.toLowerCase() - if (ltarget === 'reset') { - memoryresetframes(board) - } else if (ispresent(maybetype) && ispresent(maybeboard)) { - const ltype = maybetype.toLowerCase() - switch (ltype) { - case 'edit': - memorycreateeditframe(board, ltarget, maybeboard) - break - case 'view': - memorycreateviewframe(board, ltarget, maybeboard) - break - default: - // TODO raise error of unknown action - break - } - } - - return 0 - }) diff --git a/zss/memory/codepage.ts b/zss/memory/codepage.ts index bf850dab..783dd43c 100644 --- a/zss/memory/codepage.ts +++ b/zss/memory/codepage.ts @@ -9,7 +9,8 @@ import { BOARD, BOARD_ELEMENT } from './board' export enum CODE_PAGE_TYPE { ERROR, - FUNC, + CLI, + // all of these types support os.once() invoke as well BOARD, OBJECT, TERRAIN, @@ -40,7 +41,7 @@ export type MAYBE_CODE_PAGE = MAYBE export type CODE_PAGE_TYPE_MAP = { [CODE_PAGE_TYPE.ERROR]: string - [CODE_PAGE_TYPE.FUNC]: string + [CODE_PAGE_TYPE.CLI]: string [CODE_PAGE_TYPE.BOARD]: BOARD [CODE_PAGE_TYPE.OBJECT]: BOARD_ELEMENT [CODE_PAGE_TYPE.TERRAIN]: BOARD_ELEMENT @@ -145,6 +146,10 @@ export function codepagereadstats(codepage: MAYBE_CODE_PAGE): CODE_PAGE_STATS { // simple space separated local flag names codepage.stats.flags = lmaybename break + case 'cli': + codepage.stats.type = CODE_PAGE_TYPE.CLI + codepage.stats.name = lmaybename + break case 'func': codepage.stats.type = CODE_PAGE_TYPE.FUNC codepage.stats.name = lmaybename diff --git a/zss/memory/index.ts b/zss/memory/index.ts index 44e66b7d..fe9e796c 100644 --- a/zss/memory/index.ts +++ b/zss/memory/index.ts @@ -1,5 +1,5 @@ import { CHIP, MESSAGE } from 'zss/chip' -import { api_error } from 'zss/device/api' +import { api_error, tape_debug } from 'zss/device/api' import { WORD, createreadcontext } from 'zss/firmware/wordtypes' import { BITMAP } from 'zss/gadget/data/bitmap' import { @@ -13,7 +13,6 @@ import { createtiles, } from 'zss/gadget/data/types' import { average, unique } from 'zss/mapping/array' -import { createguid } from 'zss/mapping/guid' import { clamp } from 'zss/mapping/number' import { MAYBE, MAYBE_STRING, ispresent, isstring } from 'zss/mapping/types' import { OS } from 'zss/os' @@ -23,7 +22,6 @@ import { boarddeleteobject, MAYBE_BOARD_ELEMENT, BOARD, - BOARD_ELEMENT, MAYBE_BOARD, } from './board' import { @@ -282,13 +280,10 @@ export function memorycli( context.board = undefined context.inputcurrent = undefined - console.info('running', timestamp, id, cli) + tape_debug('memory', 'running', timestamp, id, cli) // run chip code - os.tick(id, CODE_PAGE_TYPE.FUNC, timestamp, cli) - - // halt code - os.halt(id) + os.once(id, CODE_PAGE_TYPE.CLI, timestamp, cli) } function memoryconverttogadgetlayers( diff --git a/zss/os.ts b/zss/os.ts index 7c0257d3..9ad54dbe 100644 --- a/zss/os.ts +++ b/zss/os.ts @@ -6,16 +6,19 @@ import { GeneratorBuild, compile } from './lang/generator' import { ispresent } from './mapping/types' import { CODE_PAGE_TYPE } from './memory/codepage' +export type OS_INVOKE = ( + id: string, + type: CODE_PAGE_TYPE, + timestamp: number, + code: string, +) => boolean + export type OS = { ids: () => string[] has: (id: string) => boolean halt: (id: string) => boolean - tick: ( - id: string, - type: CODE_PAGE_TYPE, - timestamp: number, - code: string, - ) => boolean + tick: OS_INVOKE + once: OS_INVOKE message: MESSAGE_FUNC } @@ -71,6 +74,10 @@ export function createos() { return !!chip?.tick(timestamp) }, + once(id, type, timestamp, code) { + const result = os.tick(id, type, timestamp, code) + return result && os.halt(id) + }, message(incoming) { const { target, path } = parsetarget(incoming.target) const targetchip: CHIP | null | undefined = chips[target]