Browse Source

More jsonifier experiments...

Mark Sibly 7 năm trước cách đây
mục cha
commit
03bfcc61e5

+ 112 - 0
src/jsonifier/comparejson.monkey2

@@ -0,0 +1,112 @@
+Namespace jsonifier
+
+Function CompareJson:Int( x:JsonObject,y:JsonValue )
+	If y=JsonValue.NullValue Return 1
+	Local r:=Cast<JsonObject>( y )
+	If Not r Return 1
+	Local xit:=x.All(),rit:=r.All()
+	While Not xit.AtEnd And Not rit.AtEnd
+		Local cmp:=xit.Current.Key<=>rit.Current.Key
+		If cmp Return cmp
+		cmp=CompareJson( xit.Current.Value,rit.Current.Value )
+		If cmp Return cmp
+		xit.Bump()
+		rit.Bump()
+	Wend
+	Return x.Count()<=>r.Count()
+End
+
+Function CompareJson:Int( x:JsonArray,y:JsonValue )
+	If y=JsonValue.NullValue Or y.IsBool Or y.IsNumber Or y.IsString Return 1
+	Local r:=Cast<JsonArray>( y )
+	If Not r Return -1
+	For Local i:=0 Until Min( x.Length,r.Length )
+		Local cmp:=CompareJson( x[i],r[i] )
+		If cmp Return cmp
+	Next
+	Return x.Length<=>r.Length
+End
+
+Function CompareJson:Int( x:JsonString,y:JsonValue )
+	If y=JsonValue.NullValue Or y.IsBool Or y.IsNumber Return 1
+	Local r:=Cast<JsonString>( y )
+	Return r ? x.Data<=>r.Data Else -1
+End
+
+Function CompareJson:Int( x:JsonNumber,y:JsonValue )
+	If y=JsonValue.NullValue Or y.IsBool Return 1
+	Local r:=Cast<JsonNumber>( y )
+	Return r ? x.Data<=>r.Data Else -1
+End
+
+Function CompareJson:Int( x:JsonBool,y:JsonValue )
+	If y=JsonValue.NullValue Return 1
+	Local r:=Cast<JsonBool>( y )
+	Return r ? x.Data<=>r.Data Else -1
+End
+
+Function CompareJson:Int( x:JsonValue,y:JsonValue )
+	If x=JsonValue.NullValue Return y=JsonValue.NullValue ? 0 Else -1
+	Local jbool:=Cast<JsonBool>( x )
+	If jbool Return CompareJson( jbool,y )
+	Local jnumber:=Cast<JsonNumber>( x )
+	If jnumber Return CompareJson( jnumber,y )
+	Local jstring:=Cast<JsonString>( x )
+	If jstring Return CompareJson( jstring,y )
+	local jarray:=Cast<JsonArray>( x )
+	If jarray Return CompareJson( jarray,y )
+	Local jobj:=Cast<JsonObject>( x )
+	If jobj Return CompareJson( jobj,y )
+	RuntimeError( "TODO" )
+	Return 0
+End
+
+#rem
+Function RndJson:JsonValue( range:Int=6 )
+	
+	Select Int( Rnd( range ) )
+	Case 0 
+		Return JsonValue.NullValue
+	Case 1 
+		Return Rnd()>.5 ? JsonBool.TrueValue Else JsonBool.FalseValue
+	Case 2 
+		Return New JsonNumber( Rnd(10000) )
+	Case 3 
+		Return New JsonString( Rnd(10000) )
+	Case 4
+		Local data:=New Stack<JsonValue>( Rnd( 10,20 ) )
+		For Local i:=0 Until data.Length
+			data[i]=RndJson( 4 )
+		Next
+		Return New JsonArray( data )
+	Case 5
+		Local data:=New StringMap<JsonValue>
+		For Local i:=0 Until Rnd( 10,20 )
+			data[ Rnd(100) ]=RndJson( 4 )
+		Next
+		Return New JsonObject( data )
+	End
+	Return Null
+End
+
+Function Main()
+	
+	Print "Start..."
+	
+	For Local i:=1 To 100000
+		
+		Local x:=RndJson()
+		Local y:=RndJson()
+		
+		Local cmp1:=CompareJson( x,y )
+		Local cmp2:=CompareJson( y,x )
+		
+		If cmp1<0 Assert( cmp2>=0 )
+		If cmp1=0 Assert( cmp2 =0 )
+		If cmp1>0 Assert( cmp2<=0 )
+	End
+	
+	Print "Success!"
+		
+End
+#end

+ 35 - 2
src/jsonifier/invocation.monkey2

@@ -29,9 +29,13 @@ Class Invocation
 		Return _decl.Invoke( _inst,_args )
 	End
 	
-	Function Ctor:Invocation( inst:Object,args:Variant[]=Null )
+	Function Ctor:Invocation( obj:Object,args:Variant[] )
 		
-		Local type:=inst.DynamicType
+		Return Ctor( obj,"New",args )
+		
+		#rem
+		
+		Local type:=obj.DynamicType
 		
 		For Local decl:=Eachin type.GetDecls( "New" )
 			
@@ -54,6 +58,35 @@ Class Invocation
 		
 		RuntimeError( "Can't find matching ctor for args" )
 		
+		Return Null
+		#end
+	End
+	
+	Function Ctor:Invocation( obj:Object,dname:String,args:Variant[] )
+		
+		Local type:=obj.DynamicType
+
+		For Local decl:=Eachin type.GetDecls( dname )
+			
+			Local ftype:=decl.Type
+			If ftype.ParamTypes.Length<>args.Length Continue
+			
+			Local match:=True
+			For Local i:=0 Until args.Length
+				If args[i]
+					If args[i].Type.ExtendsType( ftype.ParamTypes[i] ) Continue
+				Else
+					If ftype.ParamTypes[i].Kind="Class" Continue
+				Endif
+				match=False
+				Exit
+			Next
+			
+			If match Return New Invocation( type,decl,Null,args )
+		Next
+		
+		RuntimeError( "Can't find matching ctor for args" )
+		
 		Return Null
 	End
 	

+ 28 - 4
src/jsonifier/jsonifier.monkey2

@@ -18,6 +18,16 @@ Class Jsonifier
 		_insts.Add( inst )
 	End
 	
+	Method AddInstance( obj:Object,args:Variant[] )
+		
+		AddInstance( obj,Invocation.Ctor( obj,args ) )
+	end
+	
+	Method AddInstance( obj:Object,name:String,args:Variant[] )
+		
+		AddInstance( obj,Invocation.Ctor( obj,name,args ) )
+	End
+	
 	Method JsonifyInstances:JsonObject()
 		
 		Local jobj:=New JsonObject
@@ -31,7 +41,18 @@ Class Jsonifier
 			
 			jobj["type"]=New JsonString( inst.obj.DynamicType.Name )
 			jobj["ctor"]=Jsonify( inst.ctor )
-			jobj["initialState"]=JsonifyState( inst.obj )
+			
+			Local state:=JsonifyState( inst.obj ),dstate:=New JsonObject
+			
+			For Local it:=Eachin state.All()
+				
+				Local x:=it.Value
+				Local y:=inst.initialState.GetValue( it.Key )
+				
+				If CompareJson( x,y )<>0 dstate[it.Key]=x
+			Next
+			
+			jobj["state"]=dstate
 			
 			jinsts[i]=jobj
 		Next
@@ -41,7 +62,7 @@ Class Jsonifier
 		Return jobj
 	End
 	
-	Method Dejsonify( jobj:JsonObject )
+	Method DejsonifyInstances( jobj:JsonObject )
 		
 		Local jinsts:=jobj.GetArray( "instances" )
 		
@@ -54,13 +75,16 @@ Class Jsonifier
 			
 			_dejsonified.Add( obj )
 			
-			DejsonifyState( obj,jobj.GetObject( "initialState" ),obj.DynamicType )
+			DejsonifyState( obj,jobj.GetObject( "state" ),obj.DynamicType )
 		Next
 	End
 	
 	Method Jsonify:JsonValue( value:Variant )
 		
+		If Not value Return JsonValue.NullValue
+		
 		Local type:=value.Type
+		Assert( type )
 		
 		'handle primitive types
 		Select type
@@ -200,7 +224,7 @@ Class Jsonifier
 			
 			If d.Kind<>"Property" Continue
 			'Note: Add DeclInfo.Access property so we can do public fields only?
-			If Not d.Gettable Or Not d.Settable Continue
+			If Not d.Gettable Or Not d.Settable Or Not jobj.Contains( d.Name ) Continue
 			
 			d.Set( obj,Dejsonify( jobj.GetValue( d.Name ),d.Type ) )
 		Next

+ 5 - 2
src/jsonifier/jsonifierexts.monkey2

@@ -81,7 +81,7 @@ Class InvocationJsonifierExt Extends JsonifierExt
 			jobj.SetString( "scope",v.Scope.Name )
 			jobj.SetString( "decl",v.Decl.Name )
 			jobj.SetString( "type",v.Decl.Type )
-			If v.Inst jobj.SetValue( "inst",jsonifier.Jsonify( v.Inst ) )
+			jobj.SetValue( "inst",jsonifier.Jsonify( v.Inst ) )
 			jobj.SetValue( "args",jsonifier.JsonifyArray( v.Args ) )
 			
 			Return jobj
@@ -111,7 +111,9 @@ Class InvocationJsonifierExt Extends JsonifierExt
 				Exit
 			Next
 			
-			Local inst:=jsonifier.Dejsonify( jinst,decl.Type.ReturnType )
+			Local type:=dname="New" ? scope Else decl.Type.ReturnType
+			
+			Local inst:=jsonifier.Dejsonify( jinst,type )
 			
 			Local args:=New Variant[jargs.Length]
 			For Local i:=0 Until args.Length
@@ -119,6 +121,7 @@ Class InvocationJsonifierExt Extends JsonifierExt
 			Next
 			
 			Local ctor:=New Invocation( scope,decl,inst,args )
+			
 			Return ctor
 		End
 		

+ 0 - 65
src/jsonifier/statemachine.monkey2

@@ -1,65 +0,0 @@
-Namespace jsonifier
-
-Class StateMachine
-	
-	Method AddInstance( obj:Object,ctor:Invocation )
-		
-		Assert( Not _instsByObj.Contains( obj ) )
-		
-		Local inst:=New Instance
-		inst.obj=obj
-		inst.id=_insts.Length
-		inst.ctor=ctor
-		inst.initialState=JsonifyState( obj )
-		
-		_instsByObj[inst.obj]=inst
-		_instsById[inst.id]=inst
-
-		_insts.Add( inst )
-	End
-	
-	Private
-	
-	Class Instance
-		Field obj:Object
-		Field id:Int
-		Field ctor:Invocation
-		Field initialState:JsonObject
-	End
-	
-	Field _insts:=New Stack<Instance>
-	
-	Field _instsByObj:=New Map<Object,Instance>
-	Field _instsById:=New Map<Int,Instance>
-End
-
-Class StateMachineJsonifier Extends Jsonifier
-	
-	Method Jsonify:JsonValue( value:Variant,jsonifier:Jsonifier ) Override
-		
-		Local jobj:=New JsonObject
-		
-		Local jinsts:=New JsonArray( _insts.Length )
-		
-		For Local i:=0 Until jinsts.Length
-			
-			Local inst:=_insts[i]
-			Local jobj:=New JsonObject
-			
-			jobj["type"]=New JsonString( inst.obj.DynamicType.Name )
-			jobj["ctor"]=Jsonify( inst.ctor )
-			jobj["initialState"]=JsonifyState( inst.obj )
-			
-			jinsts[i]=jobj
-		Next
-
-		jobj["instances"]=jinsts
-		
-		Return jobj
-	End
-	
-
-
-End
-
-	

+ 184 - 17
src/jsonifier/test.monkey2

@@ -8,51 +8,218 @@ Namespace test
 #Import "jsonifier"
 #Import "invocation"
 #Import "jsonifierexts"
+#Import "comparejson"
 
 Using std..
 Using jsonifier..
 
+Global editing:=True
 Global jsonifier:=New Jsonifier
 
-Class C
+Class Component
 	
-	Field _parent:C
+	Method New( entity:Entity )
+		
+		_entity=entity
+		
+		_entity.AddComponent( Self )
+	End
 	
-	Field _position:Vec3f
+	Property Entity:Entity()
+		
+		Return _entity
+	End
+	
+	Protected
 	
-	Method New( parent:C )
+	Method SaveInitialState()
+		
+		If editing jsonifier.AddInstance( Self,New Variant[]( _entity ) )
+	End
+	
+	Private
+	
+	Field _entity:Entity
+	
+End
+
+Class Behaviour Extends Component
+	
+	Method New( entity:Entity )
+		
+		Super.New( entity )
+			
+		SaveInitialState()
+	End
+	
+	Property Color:Color()
+		
+		Return _color
+		
+	Setter( color:Color )
+		
+		_color=color
+	End
+	
+	Private
+	
+	Field _color:Color=graphics.Color.White
+	
+End
+
+Class Entity
+	
+	Method New( parent:Entity )
 		
 		_parent=parent
+	End
+	
+	Property Visible:Bool()
 		
-		Local ctor:=Invocation.Ctor( Self,New Variant[]( parent ) )
+		Return _visible
+	
+	Setter( visible:Bool )
 		
-		jsonifier.AddInstance( Self,ctor )
+		_visible=visible
 	End
 	
-	Property Position:Vec3f()
+	Method AddComponent<T>:T()
+		
+		Local component:=New T( Self )
 		
-		Return _position
+		Return component
+	End
+	
+	Protected
+	
+	Method SaveInitialState()
 		
-	Setter( pos:Vec3f )
+		If editing jsonifier.AddInstance( Self,New Variant[]( _parent ) )
+	End
+	
+	Private
+	
+	Field _parent:Entity
+	
+	Field _visible:Bool
+	
+	Field _components:=New Stack<Component>
+	
+	Method AddComponent( component:Component )
 		
-		_position=pos
+		_components.Add( component )
 	End
+	
+End
+
+Class Camera Extends Entity
+	
+	Method New( parent:Entity )
 
+		Super.New( parent )
+		
+		SaveInitialState()
+		
+		Visible=True
+	End
+	
 End
 
-Function Main()
+Class Light Extends Entity
 	
-	Local p:C=Null
+	Method New( parent:Entity )
+		
+		Super.New( parent )
+		
+		SaveInitialState()
+		
+		Visible=True
+	End
+
+End
+
+Class Model Extends Entity
+	
+	Method New( parent:Entity )
+		
+		Super.New( parent )
+		
+		SaveInitialState()
+		
+		Visible=True
+	End
+	
+	Function Load:Model( path:String,parent:Entity )
+		
+		Local model:=New Model( parent,True )
+		
+		If editing jsonifier.AddInstance( model,"Load",New Variant[]( path,parent ) )
+		
+		Return model
+	End
+	
+	Private
+	
+	Method New( parent:Entity,loading:Bool )
+		
+		Super.New( parent )
+	End
+
+End
+
+Function CreateScene()
 	
-	Print Typeof(p)
+	Print "CreateScene"
+
+	jsonifier=New Jsonifier
+	
+	Local camera:=New Camera( Null )
+	
+	Local light:=New Light( Null )
+	
+	Local root:=Model.Load( "blah.txt",Null )
 	
 	For Local i:=0 Until 3
-		Local c:=New C( p )
-		c.Position=New Vec3f( i,i*2,i*3 )
-		p=c
+		
+		Local model:=New Model( root )
+		
+		Local component:=New Behaviour( model )
 	Next
 	
+End
+
+Function SaveScene:JsonObject()
+	
+	Print "SaveScene"
+
 	Local jobj:=jsonifier.JsonifyInstances()
 	
-	Print jobj.ToJson()
+	Return jobj
+End
+
+Function LoadScene( jobj:JsonObject )
+	
+	Print "LoadScene"
+	
+	jsonifier=New Jsonifier
+	
+	jsonifier.DejsonifyInstances( jobj )
+End
+
+Function Main()
+	
+	CreateScene()
+	
+	Local saved1:=SaveScene()
+	
+	LoadScene( saved1 )
+	
+	Local saved2:=SaveScene()
+	
+	If CompareJson( saved1,saved2 )=0
+		Print saved1.ToJson()+"~nOkay!"
+	Else
+		Print "saved1:~n"+saved1.ToJson()+"~nsaved2:~n"+saved2.ToJson()+"~nError!"
+	Endif
+	
 End