ecs: test files

This commit is contained in:
Steven Hugg 2022-02-07 14:58:03 -06:00
parent 109e60ae10
commit 2dfe65932b
8 changed files with 520 additions and 19 deletions

View File

@ -2,7 +2,7 @@
import { mergeLocs, Tokenizer, TokenType } from "../tokenizer";
import { SourceLocated } from "../workertypes";
import { newDecoder } from "./decoder";
import { Action, ArrayType, ComponentType, DataField, DataType, DataValue, ECSError, Entity, EntityArchetype, EntityManager, EntityScope, IntType, Query, RefType, SelectType, SourceFileExport, System } from "./ecs";
import { Action, ArrayType, ComponentType, DataField, DataType, DataValue, ECSError, Entity, EntityArchetype, EntityManager, EntityScope, IntType, Query, RefType, SelectType, SELECT_TYPE, SourceFileExport, System } from "./ecs";
export enum ECSTokenType {
Ellipsis = 'ellipsis',
@ -15,6 +15,7 @@ export enum ECSTokenType {
export class ECSCompiler extends Tokenizer {
currentScope: EntityScope | null = null;
debuginfo = false;
constructor(
public readonly em: EntityManager)
@ -63,6 +64,7 @@ export class ECSCompiler extends Tokenizer {
if (!text) this.compileError(`I can't find the import file "${path}".`);
this.em.imported[path] = true;
let comp = new ECSCompiler(this.em);
comp.debuginfo = this.debuginfo; // TODO: clone compiler
try {
comp.parseFile(text, path);
} catch (e) {
@ -224,11 +226,12 @@ export class ECSCompiler extends Tokenizer {
// TODO: unused events?
let event = this.expectIdent().str;
this.expectToken('do');
let select = this.expectTokens(
['once', 'foreach', 'join', 'with', 'if', 'select']).str as SelectType; // TODO: type check?
let select = this.expectTokens(SELECT_TYPE).str as SelectType; // TODO: type check?
let query = undefined;
let join = undefined;
if (select != 'once') {
if (select == 'once') {
if (this.peekToken().str == '[') this.compileError(`A "${select}" query can't include a query.`)
} else {
query = this.parseQuery();
}
if (select == 'join') {
@ -273,12 +276,12 @@ export class ECSCompiler extends Tokenizer {
}
}
parseEvent() {
parseEventName() {
return this.expectIdent().str;
}
parseEventList() {
return this.parseList(this.parseEvent, ",");
return this.parseList(this.parseEventName, ",");
}
parseCode(): string {
@ -286,12 +289,16 @@ export class ECSCompiler extends Tokenizer {
let tok = this.expectTokenTypes([ECSTokenType.CodeFragment]);
let code = tok.str.substring(3, tok.str.length-3);
let lines = code.split('\n');
let re = /^\s*(;|\/\/|$)/; // ignore comments and blank lines
if (this.debuginfo) this.addDebugInfo(lines, tok.$loc.line);
return lines.join('\n');
}
addDebugInfo(lines: string[], startline: number) {
const re = /^\s*(;|\/\/|$)/; // ignore comments and blank lines
for (let i=0; i<lines.length; i++) {
if (!lines[i].match(re))
lines[i] = this.em.dialect.debug_line(this.path, tok.$loc.line+i) + '\n' + lines[i];
lines[i] = this.em.dialect.debug_line(this.path, startline+i) + '\n' + lines[i];
}
return lines.join('\n');
}
parseScope() : EntityScope {

View File

@ -115,7 +115,9 @@ export interface System extends SourceLocated {
tempbytes?: number;
}
export type SelectType = 'once' | 'foreach' | 'join' | 'with' | 'if' | 'select';
export const SELECT_TYPE = ['once', 'foreach', 'join', 'with', 'if', 'select'] as const;
export type SelectType = typeof SELECT_TYPE[number];
export interface ActionBase extends SourceLocated {
select: SelectType;
@ -1062,9 +1064,9 @@ export class EntityScope implements SourceLocated {
let codeeval = new ActionEval(this, sys, action);
codeeval.tmplabel = tmplabel;
codeeval.begin();
s += this.dialect.comment(`<action ${sys.name}:${event}>`); // TODO
s += this.dialect.comment(`start action ${sys.name} ${event}`); // TODO
s += codeeval.codeToString();
s += this.dialect.comment(`</action ${sys.name}:${event}>`);
s += this.dialect.comment(`end action ${sys.name} ${event}`);
// TODO: check that this happens once?
codeeval.end();
numActions++;

View File

@ -171,7 +171,7 @@ export class Tokenizer {
}
return tok;
}
expectTokens(strlist: string[], msg?: string): Token {
expectTokens(strlist: readonly string[], msg?: string): Token {
let tok = this.consumeToken();
let tokstr = tok.str;
if (!strlist.includes(tokstr)) {

View File

@ -1,4 +1,6 @@
import { readdirSync, readFileSync } from "fs";
import assert from "assert";
import { execFileSync } from "child_process";
import { readdirSync, readFileSync, writeFileSync } from "fs";
import { describe } from "mocha";
import { ECSCompiler } from "../common/ecs/compiler";
import { Dialect_CA65, EntityManager, SourceFileExport } from "../common/ecs/ecs";
@ -338,7 +340,7 @@ scope Root
end
`, 'foo.txt');
console.log('json', c.em.toJSON());
//console.log('json', c.em.toJSON());
let src = new SourceFileExport();
c.exportToFile(src);
// TODO: test?
@ -368,14 +370,27 @@ describe('Tokenizer', function() {
describe('Compiler', function() {
let testdir = './test/ecs/';
let files = readdirSync(testdir).filter(f => f.endsWith('.ecs'));
files.forEach((ecspath) => {
files.forEach((ecsfn) => {
let goodfn = ecsfn.replace('.ecs','.txt')
let srcpath = testdir + ecsfn;
let destpath = testdir + goodfn;
let dialect = new Dialect_CA65();
let em = new EntityManager(dialect);
em.mainPath = srcpath;
let compiler = new ECSCompiler(em);
let code = readFileSync(testdir + ecspath, 'utf-8');
compiler.parseFile(code, ecspath);
compiler.getImportFile = (path: string) => {
return readFileSync(testdir + path, 'utf-8');
}
let code = readFileSync(srcpath, 'utf-8');
compiler.parseFile(code, srcpath);
let out = new SourceFileExport();
em.exportToFile(out);
console.log(out.toString());
let outtxt = out.toString();
let goodtxt = readFileSync(destpath, 'utf-8');
if (outtxt.trim() != goodtxt.trim()) {
writeFileSync('/tmp/' + goodfn, outtxt, 'utf-8');
execFileSync('/usr/bin/diff', [srcpath, destpath]);
throw new Error(ecsfn + ' did not match test file');
}
});
});

View File

@ -16,6 +16,7 @@ export function assembleECS(step: BuildStep): BuildStepResult {
if (staleFiles(step, [destpath])) {
let code = getWorkFileAsString(step.path);
try {
compiler.debuginfo = true;
compiler.parseFile(code, step.path);
let outtext = compiler.export().toString();
putWorkFile(destpath, outtext);

0
test/ecs/basic1.txt Normal file
View File

235
test/ecs/vcs1.ecs Normal file
View File

@ -0,0 +1,235 @@
//#resource "vcs-ca65.h"
system Init
on main_init do once
---
.include "vcs-ca65.h"
.define PAL 0
__NMI:
__Reset:
__BRK:
CLEAN_START
{{bss_init}} ; initialize data segment
{{!start}} ; start main routine
.segment "VECTORS"
Return: .word $6060
VecNMI:
VecReset: .word Main::__Reset
VecBRK: .word Main::__BRK
---
end
component Player
end
component KernelSection
lines: 1..255
end
component BGColor
bgcolor: 0..255
end
component PFColor
pfcolor: 0..255
end
component Playfield
pf: 0..0xffffff
end
component AsymPlayfield
pfleft: 0..0xffffff
pfright: 0..0xffffff
end
component VersatilePlayfield
data: array of 0..255 baseoffset -1
end
system FrameLoop
on start do once
---
@NextFrame:
FRAME_START
{{emit preframe}}
KERNEL_START
{{emit kernel}}
KERNEL_END
{{emit postframe}}
FRAME_END
{{emit nextframe}}
jmp @NextFrame ; loop to next frame
---
end
system ResetSwitch
on nextframe do once
---
lsr SWCHB ; test Game Reset switch
bcs @NoStart
{{!resetswitch}}
@NoStart:
---
end
system ResetConsole
on resetswitch do once
---
jmp Main::__Reset ; jump to Reset handler
---
end
system JoyButton
on postframe do foreach [Player]
---
lda {{index INPT4}} ;read button input
bmi @NotPressed
{{emit joybutton}}
@NotPressed:
---
end
system Joystick
locals 1
on postframe do once
---
; 2 control inputs share a single byte, 4 bits each
lda SWCHA
sta {{$0}}
---
on postframe do foreach [Player]
---
asl {{$0}}
bcs @SkipMoveRight
{{!joyright}}
@SkipMoveRight:
asl {{$0}}
bcs @SkipMoveLeft
{{!joyleft}}
@SkipMoveLeft:
asl {{$0}}
bcs @SkipMoveDown
{{!joydown}}
@SkipMoveDown:
asl {{$0}}
bcs @SkipMoveUp
{{!joyup}}
@SkipMoveUp:
---
end
system SetHorizPos
on SetHorizPos do once
---
; SetHorizPos routine
; A = X coordinate
; Y = player number (0 or 1)
sta WSYNC ; start a new line
sec ; set carry flag
nop
@DivideLoop:
sbc #15 ; subtract 15
bcs @DivideLoop ; branch until negative
eor #7 ; calculate fine offset
asl
asl
asl
asl
sta RESP0,y ; fix coarse position
sta HMP0,y ; set fine offset
---
end
system StaticKernel
on preframe do foreach [KernelSection] limit 1
---
{{!kernelsetup}}
---
on kernel do foreach [KernelSection]
---
sta WSYNC
{{!kernelsetup}}
ldy {{<lines}}
@loop:
sta WSYNC
{{!scanline}}
dey
bne @loop
{{!kerneldone}}
---
on kernelsetup do if [BGColor]
---
lda {{<bgcolor}}
sta COLUBK
---
on kernelsetup do if [PFColor]
---
lda {{get pfcolor}}
sta COLUPF
---
on kernelsetup do if [Playfield]
---
lda {{get pf 0}}
sta PF0
lda {{get pf 8}}
sta PF1
lda {{get pf 16}}
sta PF2
---
end
///
demo Main
using FrameLoop, ResetSwitch, ResetConsole
using StaticKernel, JoyButton
entity [Player]
end
entity [KernelSection,BGColor]
const lines = 2
const bgcolor = $18
end
entity [KernelSection,BGColor]
const lines = 2
const bgcolor = $16
end
entity [KernelSection,BGColor]
const lines = 2
const bgcolor = $14
end
entity [KernelSection,BGColor]
const lines = 2
const bgcolor = $12
end
entity [KernelSection,BGColor,Playfield]
const lines = 10
const bgcolor = $14
const pf = 0x125244
end
entity Trees [KernelSection,BGColor,PFColor,Playfield]
const lines = 50
const bgcolor = $14
const pf = 0x112244
end
entity [KernelSection,BGColor,PFColor,Playfield]
const lines = 50
const bgcolor = $16
const pf = 0x124
end
entity [KernelSection,BGColor,Playfield]
const lines = 10
const bgcolor = $18
const pf = 0
end
system Local
locals 1
on joybutton do foreach [PFColor] limit 1 ---
inc {{$0}}
inc {{set Trees.pfcolor}}
---
end
end

241
test/ecs/vcs1.txt Normal file
View File

@ -0,0 +1,241 @@
.scope Main
.zeropage
PFColor_pfcolor_b0:
.res 1
.res 1
Local_tmp:
.res 1
.code
KernelSection_lines_b0:
.byte 2
.byte 2
.byte 2
.byte 2
.byte 10
.byte 50
.byte 50
.byte 10
BGColor_bgcolor_b0:
.byte 24
.byte 22
.byte 20
.byte 18
.byte 20
.byte 20
.byte 22
.byte 24
Playfield_pf_b0:
.byte 68
.byte 68
.byte 36
.byte 0
Playfield_pf_b8:
.byte 82
.byte 34
.byte 1
.byte 0
Playfield_pf_b16:
.byte 18
.byte 17
.byte 0
.byte 0
Main__INITDATA:
.byte 0
.byte 0
__Start:
.code
;;; start action Init main_init
.include "vcs-ca65.h"
.define PAL 0
__NMI:
__Reset:
__BRK:
CLEAN_START
ldy #2
: lda Main__INITDATA-1,y
sta PFColor_pfcolor_b0-1,y
dey
bne :-
; initialize data segment
.code
;;; start action FrameLoop start
FrameLoop__start__2__NextFrame:
FRAME_START
.code
;;; start action StaticKernel preframe
.code
;;; start action StaticKernel kernelsetup
lda #24
sta COLUBK
;;; end action StaticKernel kernelsetup
;;; start action StaticKernel kernelsetup
cpx #0+2
bcs StaticKernel__kernelsetup__5____skipxhi
cpx #0
bcc StaticKernel__kernelsetup__5____skipxlo
lda PFColor_pfcolor_b0,x
sta COLUPF
StaticKernel__kernelsetup__5____skipxlo:
StaticKernel__kernelsetup__5____skipxhi:
;;; end action StaticKernel kernelsetup
;;; start action StaticKernel kernelsetup
cpx #0+4
bcs StaticKernel__kernelsetup__6____skipxhi
cpx #0
bcc StaticKernel__kernelsetup__6____skipxlo
lda Playfield_pf_b0,x
sta PF0
lda Playfield_pf_b8,x
sta PF1
lda Playfield_pf_b16,x
sta PF2
StaticKernel__kernelsetup__6____skipxlo:
StaticKernel__kernelsetup__6____skipxhi:
;;; end action StaticKernel kernelsetup
;;; end action StaticKernel preframe
KERNEL_START
.code
;;; start action StaticKernel kernel
ldx #0
StaticKernel__kernel__7____each:
sta WSYNC
.code
;;; start action StaticKernel kernelsetup
lda BGColor_bgcolor_b0,x
sta COLUBK
;;; end action StaticKernel kernelsetup
;;; start action StaticKernel kernelsetup
cpx #5+2
bcs StaticKernel__kernelsetup__9____skipxhi
cpx #5
bcc StaticKernel__kernelsetup__9____skipxlo
lda PFColor_pfcolor_b0-5,x
sta COLUPF
StaticKernel__kernelsetup__9____skipxlo:
StaticKernel__kernelsetup__9____skipxhi:
;;; end action StaticKernel kernelsetup
;;; start action StaticKernel kernelsetup
cpx #4
bcc StaticKernel__kernelsetup__10____skipxlo
lda Playfield_pf_b0-4,x
sta PF0
lda Playfield_pf_b8-4,x
sta PF1
lda Playfield_pf_b16-4,x
sta PF2
StaticKernel__kernelsetup__10____skipxlo:
;;; end action StaticKernel kernelsetup
ldy KernelSection_lines_b0,x
StaticKernel__kernel__7__loop:
sta WSYNC
dey
bne StaticKernel__kernel__7__loop
inx
cpx #8
bne StaticKernel__kernel__7____each
StaticKernel__kernel__7____exit:
;;; end action StaticKernel kernel
KERNEL_END
.code
;;; start action JoyButton postframe
lda INPT4 ;read button input
bmi JoyButton__postframe__11__NotPressed
.code
;;; start action Local joybutton
inc Local_tmp+0
inc PFColor_pfcolor_b0
;;; end action Local joybutton
JoyButton__postframe__11__NotPressed:
;;; end action JoyButton postframe
FRAME_END
.code
;;; start action ResetSwitch nextframe
lsr SWCHB ; test Game Reset switch
bcs ResetSwitch__nextframe__13__NoStart
.code
;;; start action ResetConsole resetswitch
jmp Main::__Reset ; jump to Reset handler
;;; end action ResetConsole resetswitch
ResetSwitch__nextframe__13__NoStart:
;;; end action ResetSwitch nextframe
jmp FrameLoop__start__2__NextFrame ; loop to next frame
;;; end action FrameLoop start
; start main routine
.segment "VECTORS"
Return: .word $6060
VecNMI:
VecReset: .word Main::__Reset
VecBRK: .word Main::__BRK
;;; end action Init main_init
.endscope
Main__Start = Main::__Start