From c25bf15b21a95c89d011d811819a456a61ecfbdc Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Sun, 24 Jun 2018 16:47:55 +0000 Subject: [PATCH] fixed a compiler bug in handling 'and' and 'or' - it didn't emit POP_STACKTOP after JUMP_FORWARD_IF_XXX. improved some methods in some collection classes --- moo/kernel/Collect.moo | 151 ++++++++++++++++++++++++++++++----------- moo/lib/comp.c | 3 +- 2 files changed, 115 insertions(+), 39 deletions(-) diff --git a/moo/kernel/Collect.moo b/moo/kernel/Collect.moo index 1fe1db9..7304a75 100644 --- a/moo/kernel/Collect.moo +++ b/moo/kernel/Collect.moo @@ -27,7 +27,7 @@ class Collection(Object) } ## =================================================================== - ## ENUMERATION + ## ENUMERATING ## =================================================================== method do: block @@ -38,7 +38,8 @@ class Collection(Object) method collect: block { | coll | - coll := self class new: self basicSize. + ##coll := self class new: self basicSize. + coll := self class new. self do: [ :el | coll add: (block value: el) ]. ^coll } @@ -58,7 +59,8 @@ class Collection(Object) method select: condition_block { | coll | - coll := self class new: self basicSize. + ##coll := self class new: self basicSize. + coll := self class new. self do: [ :el | if (condition_block value: el) { coll add: el } ]. ^coll } @@ -66,7 +68,8 @@ class Collection(Object) method reject: condition_block { | coll | - coll := self class new: self basicSize. + ##coll := self class new: self basicSize. + coll := self class new. self do: [ :el | ifnot (condition_block value: el) { coll add: el } ]. ^coll } @@ -546,38 +549,45 @@ class OrderedCollection(SequenceableCollection) ## ------------------------------------------------ ## ENUMERATING ## ------------------------------------------------ - method do: block + method collect: aBlock { - ##^self.firstIndex to: (self.lastIndex - 1) do: [:i | block value: (self.buffer at: i)]. + | coll | + coll := self class new: self capacity. + self do: [ :el | coll add: (aBlock value: el) ]. + ^coll + } + + method do: aBlock + { + ##^self.firstIndex to: (self.lastIndex - 1) do: [:i | aBlock value: (self.buffer at: i)]. | i | i := self.firstIndex. while (i < self.lastIndex) { - block value: (self.buffer at: i). + aBlock value: (self.buffer at: i). i := i + 1. }. } - method reverseDo: block + method reverseDo: aBlock { | i | i := self.lastIndex. while (i > self.firstIndex) { i := i - 1. - block value: (self.buffer at: i). + aBlock value: (self.buffer at: i). }. - } - method keysAndValuesDo: block + method keysAndValuesDo: aBlock { | i | i := self.firstIndex. while (i < self.lastIndex) { - block value: (i - self.firstIndex) value: (self.buffer at: i). + aBlock value: (i - self.firstIndex) value: (self.buffer at: i). i := i + 1. }. } @@ -703,16 +713,16 @@ class Set(Collection) ^self new: 16. ### TODO: default size. } - method(#class) new: size + method(#class) new: capacity { - ^super new __init_with_capacity: size. + ^super new __init_with_capacity: capacity. } - method __init_with_capacity: size + method __init_with_capacity: capacity { - if (size <= 0) { size := 2 }. + if (capacity <= 0) { capacity := 2 }. self.tally := 0. - self.bucket := Array new: size. + self.bucket := Array new: capacity. } method isEmpty @@ -725,6 +735,11 @@ class Set(Collection) ^self.tally } + method capacity + { + ^self.bucket size. + } + method __make_expanded_bucket: bs { | newbuc newsz ass index i | @@ -820,6 +835,10 @@ class Set(Collection) method add: anObject { | index absent bs | + + ## you cannot add nil to a set. however, the add: method doesn't + ## raise an exception for this. the includes: for nil returns + ## false naturally for the way it's implemented. if (anObject isNil) { ^anObject }. index := self __find_index_for_add: anObject. @@ -876,26 +895,42 @@ class Set(Collection) i := i + 1. }. } + + method collect: aBlock + { + ## override the default implementation to avoid frequent growth + ## of the new collection being constructed. the block tends to + ## include expression that will produce a unique value for each + ## element. so sizing the returning collection to the same size + ## as the receiver is likely to help. however, this assumption + ## isn't always true. + + | coll | + coll := self class new: self capacity. + self do: [ :el | coll add: (aBlock value: el) ]. + ^coll + } } class AssociativeCollection(Collection) { var tally, bucket. - method new + method(#class) new { ^self new: 16. } - method(#class) new: size + + method(#class) new: capacity { - ^super new __init_with_capacity: size. + ^super new __init_with_capacity: capacity. } - method __init_with_capacity: size + method __init_with_capacity: capacity { - if (size <= 0) { size := 2 }. + if (capacity <= 0) { capacity := 2 }. self.tally := 0. - self.bucket := Array new: size. + self.bucket := Array new: capacity. } method size @@ -903,6 +938,11 @@ class AssociativeCollection(Collection) ^self.tally } + method capacity + { + ^self.bucket size. + } + method __make_expanded_bucket: bs { | newbuc newsz ass index i | @@ -945,8 +985,7 @@ class AssociativeCollection(Collection) index := (index + 1) rem: bs. }. - ##upsert ifFalse: [^ErrorCode.NOENT]. - if (upsert) {} else { ^Error.Code.ENOENT }. + ifnot (upsert) { ^Error.Code.ENOENT }. ntally := self.tally + 1. if (ntally >= bs) @@ -995,7 +1034,7 @@ class AssociativeCollection(Collection) method at: key put: value { - (* returns the affected/inserted association *) + ## returns the affected/inserted association ^self __find: key or_upsert: true with: value. } @@ -1012,7 +1051,7 @@ class AssociativeCollection(Collection) ass := self __find: (assoc key) or_upsert: false with: nil. ^ass = assoc. } - + method includesKey: key value: value { | ass | @@ -1065,11 +1104,11 @@ class AssociativeCollection(Collection) i := i + 1. }. - + self.bucket at: x put: nil. self.tally := self.tally - 1. - - (* return the affected association *) + + ## return the affected association ^v } @@ -1115,38 +1154,74 @@ class AssociativeCollection(Collection) ^self removeKey: (assoc key) ifAbsent: error_block } - method do: block + + ## =================================================================== + ## ENUMERATING + ## =================================================================== + + method collect: aBlock + { + | coll | + coll := OrderedCollection new: self capacity. + self do: [ :el | coll add: (aBlock value: el) ]. + ^coll + } + + method select: aBlock + { + | coll | + coll := self class new. + ## TODO: using at:put: here isn't really right. implement add: to be able to insert the assocication without + ## creating another new association. + ##self associationsDo: [ :ass | if (aBlock value: ass value) { coll add: ass } ]. + self associationsDo: [ :ass | if (aBlock value: ass value) { coll at: (ass key) put: (ass value) } ]. + ^coll + } + + method do: aBlock { | bs i ass | bs := self.bucket size. i := 0. while (i < bs) { - if ((ass := self.bucket at: i) notNil) { block value: ass value }. + if ((ass := self.bucket at: i) notNil) { aBlock value: ass value }. i := i + 1. }. } - method keysDo: block + method keysDo: aBlock { | bs i ass | bs := self.bucket size. i := 0. while (i < bs) { - if ((ass := self.bucket at: i) notNil) { block value: ass key }. + if ((ass := self.bucket at: i) notNil) { aBlock value: ass key }. i := i + 1. }. } - method keysAndValuesDo: block + method keysAndValuesDo: aBlock { | bs i ass | bs := self.bucket size. i := 0. while (i < bs) { - if ((ass := self.bucket at: i) notNil) { block value: ass key value: ass value }. + if ((ass := self.bucket at: i) notNil) { aBlock value: ass key value: ass value }. + i := i + 1. + }. + } + + method associationsDo: aBlock + { + | bs i ass | + bs := self.bucket size. + i := 0. + while (i < bs) + { + if ((ass := self.bucket at: i) notNil) { aBlock value: ass }. i := i + 1. }. } @@ -1166,9 +1241,9 @@ class Dictionary(AssociativeCollection) ## TODO: implement Dictionary as a Hashed List/Table or Red-Black Tree ## Do not inherit Set upon reimplementation ## - method(#class) new: size + method(#class) new: capacity { - ^super new: (size + 10). + ^super new: (capacity + 10). } (* put_assoc: is called internally by VM to add an association diff --git a/moo/lib/comp.c b/moo/lib/comp.c index 0cf86d4..8301739 100644 --- a/moo/lib/comp.c +++ b/moo/lib/comp.c @@ -5549,7 +5549,8 @@ start_over: bcode = (TOKEN_TYPE(moo) == MOO_IOTOK_AND)? BCODE_JUMP_FORWARD_IF_FALSE: BCODE_JUMP_FORWARD_IF_TRUE; /* TODO: optimization if the expression is a known constant that can be determined to be boolean */ if (add_to_oow_pool(moo, &jumptoend, moo->c->mth.code.len) <= -1 || - emit_single_param_instruction(moo, bcode, MAX_CODE_JUMP) <= -1) goto oops; + emit_single_param_instruction(moo, bcode, MAX_CODE_JUMP) <= -1 || + emit_byte_instruction(moo, BCODE_POP_STACKTOP) <= -1) goto oops; GET_TOKEN (moo); /* compile_method_expression() calls this function with a non-null