#!/usr/bin/env ascript
sys.echo(false)
print_func(func:function) = printf('%s = %s\n', func, func.expr())
tester(test:expr):map:dynamic_scope = printf("%s .. %s\n", test, eval(test)):nomap

lambda {
	A = class {
		__init__() = {
			self.prop = 'property'
		}
		__getprop__(symbol:symbol) = {
			lambda(args*) {
				symbol.tostring() + ' OK (' + args.join(',') + ') ' + self.prop
			}
		}
		func1(args*) = 'func1 OK (' + args.join(',') + ') ' + self.prop
		func2(args*) = 'func2 OK (' + args.join(',') + ') ' + self.prop
	}
	a = A()
	tester(`a.call!(`dynamic1, 1, 2, 3, 4))
	tester(`a.call!(`dynamic2, 1, 2, 3, 4))
	tester(`a.call!(`func1, 1, 2, 3, 4))
	tester(`a.call!(`func2, 1, 2, 3, 4))
}()
lambda {
	A = class {
		__getitem__(index:string) = {
			'indexed at ' + index
		}
		__setitem__(index:string, value) = {
			println(index, ' = ', value)
		}
	}
	a = A()
	tester(`a['hello'])
	tester(`a['hoge'])
	tester(`a[[1, 2]])
	a['foo'] = 'aaaaa'
	a['bar'] = 'bbbbb'
	a['aaa', 'bbb'] = 3
}()
lambda {
	x = classref(`string)
	x.len2() = self.len() * 2
	x.len3() = self.len() * 3
	tester(`"hello world".len())
	tester(`"hello world".len2())
	tester(`"hello world".len3())
}()
lambda {
	A = class {
		inst = nil
		__init__(name:string) = {
			self.name = name
		}
		getInst():static = {
			self.inst = self.inst || A("hoge")
			self.inst
		}
		print() = println(self.name)
	}
	a = A.getInst()
	a.print()
	a.name = 'mod-hoge'
	b = A.getInst()
	b.print()
}()
lambda {
	A = class {
		__setprop__(symbol:symbol, value) = {
			printf('__setprop__: %s = %s\n', symbol, value)
			true
		}
		__getprop__(symbol:symbol) = {
			'symbol-' + symbol.tostring()
		}
	}
	a = A()
	a.hoge = 2
	a.foo = 'hello world'
	println(a.hoge)
	println(a.foo)
}()
lambda {
	A = class {
		__getprop__(symbol:symbol) = {
			lambda { println('symbol-' + symbol.tostring()) }
		}
	}
	a = A()
	a.func_hoge()
	a.func_foo()
}()
lambda {
	A = class {
		func1(n:number) = {
			if (n == 0) {
				printf("%d is zero\n", n)
			} else {
				printf("%d is not zero\n", n)
			}
		}
		func2(n:number):static = {
			if (n == 0) {
				printf("%d is zero\n", n)
			} else {
				printf("%d is not zero\n", n)
			}
		}
	}
	a = A()
	a.func1(0)
	a.func1(2)
	A.func2(0)
	A.func2(2)
}()
lambda {
	obj = object()
	syms = tosymbol(format('attr%02d', 0..99))
	for (sym in syms) {|i| obj.setprop!(sym, i) }
	println((syms::tostring() + '=' + obj.getprop!(syms)).join(','))
}()
lambda {
	Person = struct(name:string, workplace:string)
	Teacher = class(Person) {
		__init__(name:string) = {|name, "school"|}
	}
	Businessman = class(Person) {
		__init__(name:string) = {|name, "office"|}
	}
	Lawyer = class(Person) {
		__init__(name:string) = {|name, "court"|}
	}
	people = [ Teacher("Yamada"), Businessman("Honda"), Lawyer("Kimura") ]
	println(people::tolist()::join(" works at "))
}()
lambda {
	Person1 = class {
		__init__(name:string, age:number) = {
			self.name = name, self.age = age
		}
		__str__() = format("name: %s, age:%s", self.name, self.age)
	}
	p1 = Person1("yamada", 30)
	printf("%s %s\n", typename(p1), p1)
	Person2 = struct(name:string, age:number) {
		__str__() = format("name: %s, age:%s", self.name, self.age)
	}
	p2 = Person2("yamada", 30)
	printf("%s %s\n", typename(p2), p2)
}()
lambda {
	B = class {
		cntAll = 0
		__init__() = {
			self.n = self.cntAll
			self.cntAll += 1
		}
		print() = printf("%d\n", self.n)
	}
	B().print()
	B().print()
	B().print()
	B().print()
	B().print()
	B().print()
	B().print()
}()
lambda {
	Person = class {
		__init__(name:string) = {
			self.name = name
		}
		introduce() = format("my name is %s", self.name)
		work() = "do what?"
	}
	Student = class(Person) {
		__init__(name:string) = {|name|}
		work() = "study"
	}
	Worker = class(Person) {
		__init__(name:string, workplace:string) = {|name|
			self.workplace = workplace
		}
		work() = format("work at %s", self.workplace)
	}
	Teacher = class(Worker) {
		__init__(name:string) = {|name, "school"|}
	}
	Businessman = class(Worker) {
		__init__(name:string) = {|name, "office"|}
	}
	f(p:Person):map = p.introduce()
	people = [
		Person("Hayasaka Hiroko")
		Student("Kikuchi Takao")
		Teacher("Nagao Erika")
		Businessman("Kikuchi Shigeo")
	]
	tester(`f(people))
	tester(`isinstance(people, `number))
	tester(`isinstance(people, `string))
	tester(`isinstance(people, `object))
	tester(`isinstance(people, `Person))
	tester(`isinstance(people, `Student))
	tester(`isinstance(people, `Worker))
	tester(`isinstance(people, `Businessman))
	tester(`isinstance(people, `Teacher))
	tester(`people::work())
}()
lambda {
	Person = class {
		__init__(job, name, age) = {
			self.job = job, self.name = name, self.age = age
		}
		Print() = printf("job:%s, name:%s, age:%d\n", self.job, self.name, self.age)
	}
	Student = class(Person) {
		__init__(name, age) = {|"student", name, age|
		}
	}
	Teacher = class(Person) {
		__init__(name, age) = {|"teacher", name, age|
		}
	}
	list = [
		Student("Hayasaka Hiroko",	14)
		Teacher("Hannda Yumiko",	40)
		Student("Honma Chise",		13)
		Student("Kikuchi Takao",	15)
		Teacher("Aoi Tatsuya",		30)
	]
	list::Print()
}()
lambda {
	A = class {
		nn = 0
		__init__() = {
			self.n = self.nn, self.nn += 1
			printf("+created %d\n", self.n)
		}
		__del__() = {
			printf("-deleted %d\n", self.n)
		}
		Print() = {
			printf(" print   %d\n", self.n)
		}
	}
	lambda {
		lambda {
			a = A()
			a.Print()
			a = A()
			a.Print()
			A().Print()
			printf("----\n")
		}()
		lambda {
			a = A()
			a.Print()
			a = A()
			a.Print()
			A().Print()
			printf("----\n")
		}()
		printf("done\n")
	}()
	repeat(3) {
		a = A()
	}
	printf("----\n")
}()
lambda {
	f(x) = class {
		__init__() = { self.x = x }
	}
	A5 = f(5)
	A3 = f(3)
	println("test of class closure")
	print_func(f)
	tester(`A5().x)
	tester(`A3().x)
}()
lambda {
	Person = class {
		__init__(name:string, age:number) = {
			self.name = name
			self.age = age
		}
		Print() = {
			print(self.name, " is ", self.age, " years old.\n")
		}
	}
	people = @(Person) {
		["hoge",	15]		# comma at each end of line can be omitted
		["aaaa",	18]
		["saito",	19]
		["tanaka",	20]
		["sato",	17]
	}
	println("before sort")
	people::Print()
	println("sort by name")
	people.sort(&{$person1.name <=> $person2.name})::Print()
	println("sort by age")
	people.sort(&{$person1.age <=> $person2.age})::Print()
}()
lambda {
	Object = class()
	obj = Object()
	obj.a = 10
	obj.b = 20
	obj.func1(x) = math.sin(x)
	obj.func2(x) = math.sqrt(x)
	obj.func3() = math.sqrt(self.a)
	print("obj.a + obj.b = ", obj.a + obj.b, "\n")
	println(obj.func1(3))
	println(obj.func2(2))
	println(obj.func3())
	println("--------")
}()
lambda {
	Person = class {
		name = "aaa"
		age = 10
		__str__() = format("name: %s, age:%s", self.name, self.age)
		Print() = {
			print(self.name, " is ", self.age, " years old", "  pi=", math.pi, "\n")
		}
	}
	a = Person()
	println(a)
	print("a.name = ", a.name, "\n")
	print("a.age = ", a.age, "\n")
	a.Print()
	a.name = "bbbb"
	a.Print()
	println("--------")
}()
lambda {
	Person = class {
		__init__(name) = {
			print("Person constructor\n")
			self.name = name
			self.cnt = 0
		}
		__del__() = {
			print("Person destructor\n")
		}
		func(n) = {
			print("Person#func() cnt = ", self.cnt, "\n")
			self.cnt = self.cnt + n
		}
		Print() = {
			print("My name is ", self.name, "\n")
		}
	}
	p = Person("Yutaka")
	p.Print()
	repeat (10) {
		p.func(1)
	}
	#p.Print("hoge")
}()
lambda {
	[A, B, C] = [class(), class(), class()]
	println(A())
	println(B())
	println(C())
}()
lambda {
	Axis = class {
		__init__(title) = {
			self.title = title
			self.axis_step = 1
			self.guide_step = 10
			self.min = 0
			self.max = 100
			self.samples = 10
		}
		Print() = {
			print(
				"axis.title=",		self.title,
				", axis_step=",		self.axis_step,
				", guide_step=",	self.guide_step,
				", min=",			self.min,
				", max=",			self.max,
				", samples=",		self.samples, "\n")
			println([interval(self.min, self.max, self.samples)].tostring())
		}
	}
	Graph = class {
		__init__(title) = {
			self.title = title
			self.x = Axis("x-title")
			self.y = Axis("y-title")
			self.z = Axis("z-title")
		}
		Print() = {
			print("title=", self.title, "\n")
			self.x.Print()
			self.y.Print()
			self.z.Print()
		}
	}
	g = Graph("hogehoge")
	g.Print()
	println("--------")
}()
/*
lambda {
	Graph = class {
		Axis = class {
			__init__(title) = {
				self.title = title
				self.axis_step = 1
				self.guide_step = 10
				self.min = 0
				self.max = 100
				self.samples = 10
			}
			Print() = {
				print(
					"axis.title=",		self.title,
					", axis_step=",		self.axis_step,
					", guide_step=",	self.guide_step,
					", min=",			self.min,
					", max=",			self.max,
					", samples=",		self.samples, "\n")
				println([interval(self.min, self.max, self.samples)].tostring())
			}
		}
		__init__(title) = {
			self.title = title
			self.x = self.Axis("x-title")
			self.y = self.Axis("y-title")
			self.z = self.Axis("z-title")
		}
		Print() = {
			print("title=", self.title, "\n")
			self.x.Print()
			self.y.Print()
			self.z.Print()
		}
	}
	g = Graph("hogehoge")
	g.Print()
	println("--------")
}()
*/
lambda {
	A = class {
		func(x) = { print("A.func(", x, ")\n") }
	}
	a = A()
	for (x in range(1, 5)) {
		a.func(x)
	}
	println("--------")
}()
lambda {
	ListEx = class(List) {
		__init__() = {
			#super()
			repeat(3) { self.add("init") }
		}
		__del__() = {
			println("destroyed")
		}
	}
	a = ListEx()
	repeat(5) { a.add("1", "2", "3") }
	println(a)
}
lambda {
	A = class {
		val1 = 1
		val2 = "hello"
		func1():static = { println(self.val1) }
		func2() = { println(self.val2) }
	}
	A.func1()
	A().func2()
	A.hoge = 1
	print(`A.hoge, " = ", A.hoge, "\n")
	A.hoge += 1
	print(`A.hoge, " = ", A.hoge, "\n")
	try {
		A.func2()
	} except (ValueError) {
		println("expected error occurs")
	}
}()
println("<<end of script>>")
